Browse Source

check PulseAudio bridged with first group name, enable 'undo' if changes and 'save' if changes are correct. Purpose directly pertinent group add if no sink or no source exists

pull/290/head^2
houston 4 years ago
parent
commit
213ad9a604
2 changed files with 108 additions and 27 deletions
  1. +89
    -12
      src/bridgesourcesink.py
  2. +19
    -15
      src/cadence.py

+ 89
- 12
src/bridgesourcesink.py View File

@@ -21,7 +21,7 @@


from collections import namedtuple from collections import namedtuple


from PyQt5.QtCore import Qt, QRegExp
from PyQt5.QtCore import Qt, QRegExp, pyqtSignal
from PyQt5.QtGui import QRegExpValidator from PyQt5.QtGui import QRegExpValidator
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHeaderView, QComboBox, QLineEdit, QSpinBox, QPushButton, QCheckBox, QHBoxLayout, QWidget from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHeaderView, QComboBox, QLineEdit, QSpinBox, QPushButton, QCheckBox, QHBoxLayout, QWidget
from shared import * from shared import *
@@ -61,6 +61,8 @@ class BridgeSourceSink(QTableWidget):
channels="2", channels="2",
connected="True") connected="True")


customChanged = pyqtSignal()

def __init__(self, parent): def __init__(self, parent):
QTableWidget.__init__(self, parent) QTableWidget.__init__(self, parent)
self.bridgeData = [] self.bridgeData = []
@@ -79,7 +81,7 @@ class BridgeSourceSink(QTableWidget):
# Name # Name
name_col = QLineEdit() name_col = QLineEdit()
name_col.setText(data.name) name_col.setText(data.name)
name_col.returnPressed.connect(self.enable_buttons)
name_col.textChanged.connect(self.customChanged.emit)
rx = QRegExp("[^|]+") rx = QRegExp("[^|]+")
validator = QRegExpValidator(rx, self) validator = QRegExpValidator(rx, self)
name_col.setValidator(validator) name_col.setValidator(validator)
@@ -100,21 +102,22 @@ class BridgeSourceSink(QTableWidget):
combo_box.addItem(loudspeaker_icon, "sink") combo_box.addItem(loudspeaker_icon, "sink")
combo_box.setCurrentIndex(0 if data.s_type == "source" else 1) combo_box.setCurrentIndex(0 if data.s_type == "source" else 1)
combo_box.currentTextChanged.connect(self.enable_buttons)
combo_box.currentTextChanged.connect(self.customChanged.emit)
self.setCellWidget(row, 1, combo_box) self.setCellWidget(row, 1, combo_box)


# Channels # Channels
chan_col = QSpinBox() chan_col = QSpinBox()
chan_col.setValue(int(data.channels)) chan_col.setValue(int(data.channels))
chan_col.setMinimum(1) chan_col.setMinimum(1)
chan_col.valueChanged.connect(self.enable_buttons)
chan_col.setAlignment(Qt.AlignCenter)
chan_col.valueChanged.connect(self.customChanged.emit)
self.setCellWidget(row, 2, chan_col) self.setCellWidget(row, 2, chan_col)


# Auto connect? # Auto connect?
auto_cb = QCheckBox() auto_cb = QCheckBox()
auto_cb.setObjectName("auto_cb") auto_cb.setObjectName("auto_cb")
auto_cb.setCheckState(Qt.Checked if data.connected in ['true', 'True', 'TRUE'] else Qt.Unchecked) auto_cb.setCheckState(Qt.Checked if data.connected in ['true', 'True', 'TRUE'] else Qt.Unchecked)
auto_cb.stateChanged.connect(self.enable_buttons)
auto_cb.stateChanged.connect(self.customChanged.emit)
widget = QWidget() widget = QWidget()
h_layout = QHBoxLayout(widget) h_layout = QHBoxLayout(widget)
h_layout.addWidget(auto_cb) h_layout.addWidget(auto_cb)
@@ -124,19 +127,15 @@ class BridgeSourceSink(QTableWidget):
self.setCellWidget(row, 3, widget) self.setCellWidget(row, 3, widget)
self.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) self.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)


def enable_buttons(self):
# Can't work out how to tell the table that data has changed (to cause the buttons to become enabled),
# so instead manually make the buttons enabled.
for btn_name in ["b_bridge_save", "b_bridge_undo"]:
self.parent().findChild(QPushButton, btn_name).setProperty("enabled", True)

def defaults(self): def defaults(self):
self.bridgeData = [self.defaultPASourceData, self.defaultPASinkData] self.bridgeData = [self.defaultPASourceData, self.defaultPASinkData]
self.load_data_into_cells() self.load_data_into_cells()
self.customChanged.emit()


def undo(self): def undo(self):
self.load_from_settings() self.load_from_settings()
self.load_data_into_cells() self.load_data_into_cells()
self.customChanged.emit()


def initialise_settings(self): def initialise_settings(self):
GlobalSettings.setValue( GlobalSettings.setValue(
@@ -147,14 +146,91 @@ class BridgeSourceSink(QTableWidget):
bridgeDataText = GlobalSettings.value("Pulse2JACK/PABridges") bridgeDataText = GlobalSettings.value("Pulse2JACK/PABridges")
self.bridgeData = self.decode_bridge_data(bridgeDataText) self.bridgeData = self.decode_bridge_data(bridgeDataText)


def hasChanges(self)->bool:
bridgeDataText = GlobalSettings.value("Pulse2JACK/PABridges")
saved_data = self.decode_bridge_data(bridgeDataText)

if self.rowCount() != len(saved_data):
return True

for row in range(self.rowCount()):
orig_data = saved_data[row]

name = self.cellWidget(row, 0).text()
if name != orig_data[0]:
return True

type = self.cellWidget(row, 1).currentText()
if type != orig_data[1]:
return True

channels = self.cellWidget(row, 2).value()
if channels != int(orig_data[2]):
return True

auto_cb = self.cellWidget(row, 3).findChild(QCheckBox, "auto_cb")
connected = auto_cb.isChecked()
if connected != bool(orig_data[3]):
return True

return False

def hasValidValues(self)->bool:
used_names = []

row_count = self.rowCount()
# Prevent save without any bridge
if not row_count:
return False

for row in range(row_count):
line_edit = self.cellWidget(row, 0)
name = line_edit.text()

if not name or name in used_names:
# prevent double name entries
return False

used_names.append(name)

return True

def add_row(self): def add_row(self):
self.bridgeData.append(SSData(name="", s_type="source", channels="2", connected="False"))
# first, search in table which bridge exists
# to add the most pertinent new bridge
has_source = False
has_sink = False

for row in range(self.rowCount()):
cell_widget = self.cellWidget(row, 1)

group_type = ""
if cell_widget:
group_type = cell_widget.currentText()

if group_type == "source":
has_source = True
elif group_type == "sink":
has_sink = True

if has_source and has_sink:
break

ss_data = SSData(name="", s_type="source", channels="2", connected="False")
if not has_sink:
ss_data = self.defaultPASinkData
elif not has_source:
ss_data = self.defaultPASourceData

self.bridgeData.append(ss_data)
self.load_data_into_cells() self.load_data_into_cells()
self.editItem(self.item(self.rowCount() - 1, 0)) self.editItem(self.item(self.rowCount() - 1, 0))
self.customChanged.emit()


def remove_row(self): def remove_row(self):
del self.bridgeData[self.currentRow()] del self.bridgeData[self.currentRow()]
self.load_data_into_cells() self.load_data_into_cells()
self.customChanged.emit()


def save_bridges(self): def save_bridges(self):
self.bridgeData = [] self.bridgeData = []
@@ -177,6 +253,7 @@ class BridgeSourceSink(QTableWidget):
# Need an extra line at the end # Need an extra line at the end
conn_file.write("\n") conn_file.write("\n")
conn_file.close() conn_file.close()
self.customChanged.emit()


# encode and decode from tuple so it isn't stored in the settings file as a type, and thus the # encode and decode from tuple so it isn't stored in the settings file as a type, and thus the
# configuration is backwards compatible with versions that don't understand SSData types. # configuration is backwards compatible with versions that don't understand SSData types.


+ 19
- 15
src/cadence.py View File

@@ -1139,7 +1139,7 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW):
self.b_bridge_undo.clicked.connect(self.slot_PulseAudioBridgeUndo) self.b_bridge_undo.clicked.connect(self.slot_PulseAudioBridgeUndo)
self.b_bridge_save.clicked.connect(self.slot_PulseAudioBridgeSave) self.b_bridge_save.clicked.connect(self.slot_PulseAudioBridgeSave)
self.b_bridge_defaults.clicked.connect(self.slot_PulseAudioBridgeDefaults) self.b_bridge_defaults.clicked.connect(self.slot_PulseAudioBridgeDefaults)
self.tableSinkSourceData.itemChanged.connect(self.slot_PulseAudioBridgeTableChanged)
self.tableSinkSourceData.customChanged.connect(self.slot_PulseAudioBridgeTableChanged)
self.tableSinkSourceData.doubleClicked.connect(self.slot_PulseAudioBridgeTableChanged) self.tableSinkSourceData.doubleClicked.connect(self.slot_PulseAudioBridgeTableChanged)


self.pic_catia.clicked.connect(self.func_start_catia) self.pic_catia.clicked.connect(self.func_start_catia)
@@ -1236,11 +1236,13 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW):
except: except:
version, groups, conns = (list(), list(), list()) version, groups, conns = (list(), list(), list())


pa_first_group_name = self.getFirstPulseAudioGroupName()

for group_id, group_name, ports in groups: for group_id, group_name, ports in groups:
if group_name == "alsa2jack": if group_name == "alsa2jack":
global jackClientIdALSA global jackClientIdALSA
jackClientIdALSA = group_id jackClientIdALSA = group_id
elif group_name == "PulseAudio JACK Sink":
elif group_name in (pa_first_group_name, "PulseAudio JACK Sink"):
global jackClientIdPulse global jackClientIdPulse
jackClientIdPulse = group_id jackClientIdPulse = group_id


@@ -1415,6 +1417,14 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW):
self.systray.setActionEnabled("a2j_stop", False) self.systray.setActionEnabled("a2j_stop", False)
self.label_bridge_a2j.setText(self.tr("ALSA MIDI Bridge is stopped")) self.label_bridge_a2j.setText(self.tr("ALSA MIDI Bridge is stopped"))


def getFirstPulseAudioGroupName(self)->str:
# search PulseAudio JACK first group in settings
pa_bridges_settings = GlobalSettings.value("Pulse2JACK/PABridges", type=list)
if pa_bridges_settings:
return pa_bridges_settings[0].partition('|')[0]

return "PulseAudio JACK Sink"

def checkAlsaAudio(self): def checkAlsaAudio(self):
asoundrcFile = os.path.join(HOME, ".asoundrc") asoundrcFile = os.path.join(HOME, ".asoundrc")


@@ -1626,11 +1636,13 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW):


@pyqtSlot(int, str) @pyqtSlot(int, str)
def slot_DBusJackClientAppearedCallback(self, group_id, group_name): def slot_DBusJackClientAppearedCallback(self, group_id, group_name):
pa_first_group_name = self.getFirstPulseAudioGroupName()

if group_name == "alsa2jack": if group_name == "alsa2jack":
global jackClientIdALSA global jackClientIdALSA
jackClientIdALSA = group_id jackClientIdALSA = group_id
self.checkAlsaAudio() self.checkAlsaAudio()
elif group_name == "PulseAudio JACK Sink":
elif group_name in ("PulseAudio JACK Sink", pa_first_group_name):
global jackClientIdPulse global jackClientIdPulse
jackClientIdPulse = group_id jackClientIdPulse = group_id
self.checkPulseAudio() self.checkPulseAudio()
@@ -1809,38 +1821,30 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW):


@pyqtSlot() @pyqtSlot()
def slot_PulseAudioBridgeTableChanged(self): def slot_PulseAudioBridgeTableChanged(self):
self.b_bridge_save.setEnabled(True)
self.b_bridge_undo.setEnabled(True)
has_changes = self.tableSinkSourceData.hasChanges()
has_valid_values = self.tableSinkSourceData.hasValidValues()
self.b_bridge_save.setEnabled(has_changes and has_valid_values)
self.b_bridge_undo.setEnabled(has_changes)


@pyqtSlot() @pyqtSlot()
def slot_PulseAudioBridgeAdd(self): def slot_PulseAudioBridgeAdd(self):
self.tableSinkSourceData.add_row() self.tableSinkSourceData.add_row()
self.b_bridge_save.setEnabled(True)
self.b_bridge_undo.setEnabled(True)


@pyqtSlot() @pyqtSlot()
def slot_PulseAudioBridgeRemove(self): def slot_PulseAudioBridgeRemove(self):
self.tableSinkSourceData.remove_row() self.tableSinkSourceData.remove_row()
self.b_bridge_save.setEnabled(True)
self.b_bridge_undo.setEnabled(True)


@pyqtSlot() @pyqtSlot()
def slot_PulseAudioBridgeUndo(self): def slot_PulseAudioBridgeUndo(self):
self.tableSinkSourceData.undo() self.tableSinkSourceData.undo()
self.b_bridge_save.setEnabled(False)
self.b_bridge_undo.setEnabled(False)


@pyqtSlot() @pyqtSlot()
def slot_PulseAudioBridgeSave(self): def slot_PulseAudioBridgeSave(self):
self.tableSinkSourceData.save_bridges() self.tableSinkSourceData.save_bridges()
self.b_bridge_save.setEnabled(False)
self.b_bridge_undo.setEnabled(False)


@pyqtSlot() @pyqtSlot()
def slot_PulseAudioBridgeDefaults(self): def slot_PulseAudioBridgeDefaults(self):
self.tableSinkSourceData.defaults() self.tableSinkSourceData.defaults()
self.b_bridge_save.setEnabled(True)
self.b_bridge_undo.setEnabled(True)


@pyqtSlot() @pyqtSlot()
def slot_PulseAudioBridgeOptions(self): def slot_PulseAudioBridgeOptions(self):


Loading…
Cancel
Save