Browse Source

Merge pull request #2 from Houston4444/secure_pulse_edit

Secure pulse edit
pull/290/head
Mark Fisher GitHub 4 years ago
parent
commit
d1d8fe3ca7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
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 PyQt5.QtCore import Qt, QRegExp
from PyQt5.QtCore import Qt, QRegExp, pyqtSignal
from PyQt5.QtGui import QRegExpValidator
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHeaderView, QComboBox, QLineEdit, QSpinBox, QPushButton, QCheckBox, QHBoxLayout, QWidget
from shared import *
@@ -61,6 +61,8 @@ class BridgeSourceSink(QTableWidget):
channels="2",
connected="True")

customChanged = pyqtSignal()

def __init__(self, parent):
QTableWidget.__init__(self, parent)
self.bridgeData = []
@@ -79,7 +81,7 @@ class BridgeSourceSink(QTableWidget):
# Name
name_col = QLineEdit()
name_col.setText(data.name)
name_col.returnPressed.connect(self.enable_buttons)
name_col.textChanged.connect(self.customChanged.emit)
rx = QRegExp("[^|]+")
validator = QRegExpValidator(rx, self)
name_col.setValidator(validator)
@@ -100,21 +102,22 @@ class BridgeSourceSink(QTableWidget):
combo_box.addItem(loudspeaker_icon, "sink")
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)

# Channels
chan_col = QSpinBox()
chan_col.setValue(int(data.channels))
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)

# Auto connect?
auto_cb = QCheckBox()
auto_cb.setObjectName("auto_cb")
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()
h_layout = QHBoxLayout(widget)
h_layout.addWidget(auto_cb)
@@ -124,19 +127,15 @@ class BridgeSourceSink(QTableWidget):
self.setCellWidget(row, 3, widget)
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):
self.bridgeData = [self.defaultPASourceData, self.defaultPASinkData]
self.load_data_into_cells()
self.customChanged.emit()

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

def initialise_settings(self):
GlobalSettings.setValue(
@@ -147,14 +146,91 @@ class BridgeSourceSink(QTableWidget):
bridgeDataText = GlobalSettings.value("Pulse2JACK/PABridges")
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):
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.editItem(self.item(self.rowCount() - 1, 0))
self.customChanged.emit()

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

def save_bridges(self):
self.bridgeData = []
@@ -177,6 +253,7 @@ class BridgeSourceSink(QTableWidget):
# Need an extra line at the end
conn_file.write("\n")
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
# 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_save.clicked.connect(self.slot_PulseAudioBridgeSave)
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.pic_catia.clicked.connect(self.func_start_catia)
@@ -1236,11 +1236,13 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW):
except:
version, groups, conns = (list(), list(), list())

pa_first_group_name = self.getFirstPulseAudioGroupName()

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

@@ -1415,6 +1417,14 @@ class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW):
self.systray.setActionEnabled("a2j_stop", False)
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):
asoundrcFile = os.path.join(HOME, ".asoundrc")

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

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

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

@pyqtSlot()
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()
def slot_PulseAudioBridgeAdd(self):
self.tableSinkSourceData.add_row()
self.b_bridge_save.setEnabled(True)
self.b_bridge_undo.setEnabled(True)

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

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

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

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

@pyqtSlot()
def slot_PulseAudioBridgeOptions(self):


Loading…
Cancel
Save