mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
More work on Linux TTS config
This commit is contained in:
parent
380f49b8fc
commit
1056534a71
@ -19,7 +19,7 @@ class Client:
|
||||
def escape_marked_text(cls, text):
|
||||
return prepare_string_for_xml(text)
|
||||
|
||||
def __init__(self, dispatch_on_main_thread):
|
||||
def __init__(self, dispatch_on_main_thread=lambda f: f()):
|
||||
self.status = {'synthesizing': False, 'paused': False}
|
||||
self.dispatch_on_main_thread = dispatch_on_main_thread
|
||||
self.current_marked_text = None
|
||||
@ -41,7 +41,10 @@ class Client:
|
||||
|
||||
def __del__(self):
|
||||
if self.ssip_client is not None:
|
||||
try:
|
||||
self.ssip_client.cancel()
|
||||
except Exception:
|
||||
pass
|
||||
self.ssip_client.close()
|
||||
self.ssip_client = None
|
||||
shutdown = __del__
|
||||
|
@ -2,9 +2,10 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from contextlib import suppress
|
||||
from PyQt5.Qt import (
|
||||
QAbstractTableModel, QComboBox, QFontMetrics, QFormLayout, Qt, QTableView,
|
||||
QWidget
|
||||
QAbstractItemView, QAbstractTableModel, QComboBox, QFontMetrics, QFormLayout, Qt,
|
||||
QTableView, QWidget, QSortFilterProxyModel, QItemSelectionModel
|
||||
)
|
||||
|
||||
from calibre.gui2.preferences.look_feel import BusyCursor
|
||||
@ -12,6 +13,8 @@ from calibre.gui2.preferences.look_feel import BusyCursor
|
||||
|
||||
class VoicesModel(QAbstractTableModel):
|
||||
|
||||
system_default_voice = ('', '', '')
|
||||
|
||||
def __init__(self, voice_data, default_output_module, parent=None):
|
||||
super().__init__(parent)
|
||||
self.voice_data = voice_data
|
||||
@ -19,7 +22,7 @@ class VoicesModel(QAbstractTableModel):
|
||||
self.column_headers = (_('Name'), _('Language'), _('Variant'))
|
||||
|
||||
def rowCount(self, parent=None):
|
||||
return len(self.current_voices)
|
||||
return len(self.current_voices) + 1
|
||||
|
||||
def columnCount(self, parent=None):
|
||||
return 3
|
||||
@ -32,11 +35,20 @@ class VoicesModel(QAbstractTableModel):
|
||||
def data(self, index, role=Qt.ItemDataRole.DisplayRole):
|
||||
if role == Qt.ItemDataRole.DisplayRole:
|
||||
row = index.row()
|
||||
try:
|
||||
data = self.current_voices[row]
|
||||
return data[index.column()]
|
||||
except IndexError:
|
||||
return
|
||||
with suppress(IndexError):
|
||||
if row == 0:
|
||||
return (_('System default'), '', '')[index.column()]
|
||||
data = self.current_voices[row - 1]
|
||||
ans = data[index.column()]
|
||||
if not ans or ans == 'none':
|
||||
ans = ''
|
||||
return ans
|
||||
if role == Qt.ItemDataRole.UserRole:
|
||||
row = index.row()
|
||||
with suppress(IndexError):
|
||||
if row == 0:
|
||||
return self.system_default_voice
|
||||
return self.current_voices[row - 1]
|
||||
|
||||
def change_output_module(self, om):
|
||||
self.beginResetModel()
|
||||
@ -58,15 +70,87 @@ class Widget(QWidget):
|
||||
self.voice_data = self.tts_client.get_voice_data()
|
||||
self.system_default_output_module = self.tts_client.system_default_output_module
|
||||
om.addItem(_('System default'), self.system_default_output_module)
|
||||
for x in self.voice_data:
|
||||
om.addItem(x, x)
|
||||
l.addRow(_('Speech synthesizer:'), om)
|
||||
|
||||
self.voices = v = QTableView(self)
|
||||
self.voices_model = VoicesModel(self.voice_data, self.system_default_output_module, parent=v)
|
||||
v.setModel(self.voices_model)
|
||||
self.proxy_model = p = QSortFilterProxyModel(self)
|
||||
p.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
|
||||
p.setSourceModel(self.voices_model)
|
||||
v.setModel(p)
|
||||
v.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
v.setSortingEnabled(True)
|
||||
v.horizontalHeader().resizeSection(0, QFontMetrics(self.font()).averageCharWidth() * 30)
|
||||
v.verticalHeader().close()
|
||||
v.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
v.sortByColumn(0, Qt.SortOrder.AscendingOrder)
|
||||
om.currentIndexChanged.connect(self.output_module_changed)
|
||||
l.addRow(v)
|
||||
self.backend_settings = initial_backend_settings or {}
|
||||
|
||||
def sizeHint(self):
|
||||
ans = super().sizeHint()
|
||||
ans.setHeight(max(ans.height(), 600))
|
||||
return ans
|
||||
|
||||
@property
|
||||
def selected_voice(self):
|
||||
for x in self.voices.selectedIndexes():
|
||||
return x.data(Qt.ItemDataRole.UserRole)
|
||||
|
||||
@selected_voice.setter
|
||||
def selected_voice(self, val):
|
||||
val = val or VoicesModel.system_default_voice
|
||||
idx = self.voices_model.index_for_voice(tuple(val))
|
||||
if idx is not None:
|
||||
idx = self.proxy_model.mapFromSource(idx)
|
||||
self.voices.selectionModel().select(idx, QItemSelectionModel.SelectionFlag.ClearAndSelect)
|
||||
self.voices.scrollTo(idx)
|
||||
|
||||
@property
|
||||
def selected_output_module(self):
|
||||
return self.output_modules.currentData()
|
||||
|
||||
@selected_output_module.setter
|
||||
def selected_output_module(self, val):
|
||||
if not val:
|
||||
self.output_modules.setCurrentIndex(0)
|
||||
return
|
||||
idx = self.output_modules.findData(val)
|
||||
if idx < 0:
|
||||
idx = 0
|
||||
self.output_modules.setCurrentIndex(idx)
|
||||
|
||||
def output_module_changed(self, idx):
|
||||
om = self.selected_output_module
|
||||
self.voices_model.change_output_module(om)
|
||||
|
||||
@property
|
||||
def backend_settings(self):
|
||||
ans = {}
|
||||
om = self.selected_output_module
|
||||
if om != self.system_default_output_module:
|
||||
ans['output_module'] = om
|
||||
voice = self.selected_voice
|
||||
if voice != VoicesModel.system_default_voice:
|
||||
ans['voice'] = voice
|
||||
return ans
|
||||
|
||||
@backend_settings.setter
|
||||
def backend_settings(self, val):
|
||||
om = val.get('output_module') or self.system_default_output_module
|
||||
self.selected_output_module = om
|
||||
voice = val.get('voice') or VoicesModel.system_default_voice
|
||||
self.selected_voice = voice
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from calibre.gui2 import Application
|
||||
from calibre.gui2.tts.implementation import Client
|
||||
app = Application([])
|
||||
c = Client()
|
||||
w = Widget(c, {})
|
||||
w.show()
|
||||
app.exec_()
|
||||
|
Loading…
x
Reference in New Issue
Block a user