441 lines
14 KiB
C++
Executable File
441 lines
14 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* OperatorManagement - Operator Edit Dialog
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Christian Ehrlicher, SLSE, 2016-02-29
|
|
*/
|
|
|
|
#include "audio_settings_dialog.h"
|
|
#include "ui_audio_settings_dialog.h"
|
|
#include "audio_settings_avail_streams_model.h"
|
|
#include "audio_settings_used_streams_model.h"
|
|
#include "audio_stream_type.h"
|
|
#include <LtsWidgets/lts_message_dialog.h>
|
|
#include <LtsSession/lts_session_data_dds.h>
|
|
#include <LtsSession/lts_session_data.h>
|
|
#include <AudioVideoManagement/avm_ftc_types.h>
|
|
|
|
namespace AudioVideoManagement
|
|
{
|
|
AudioSettingsDialog::AudioSettingsDialog(QWidget *parent)
|
|
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
|
, m_ui(new Ui::AudioSettingsDialog)
|
|
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
|
, m_logger(getLogger("AudioSettingsDialog"))
|
|
{
|
|
m_ui->setupUi(this);
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
setOnlineHelpFilename(QStringLiteral("Situation-Voice_Communication_Access"));
|
|
}
|
|
|
|
AudioSettingsDialog::~AudioSettingsDialog()
|
|
{
|
|
delete m_ui;
|
|
}
|
|
|
|
bool AudioSettingsDialog::init(OperatorManagement::Interface::Dtc *opmDtc,
|
|
Interface::Dtc *avmDtc,
|
|
Interface::Ftc *avmFtc,
|
|
LtsSession::LtsSessionDataDds *session)
|
|
{
|
|
Q_ASSERT(opmDtc);
|
|
Q_ASSERT(avmDtc);
|
|
Q_ASSERT(avmFtc);
|
|
Q_ASSERT(session);
|
|
|
|
setUnchangeable(true);
|
|
|
|
m_session = session;
|
|
m_avmDtc = avmDtc;
|
|
m_avmFtc = avmFtc;
|
|
////////////
|
|
// Create Model
|
|
|
|
m_modelAvailable = new AvailStreamsModel(avmDtc, m_session->exerciseId(), this);
|
|
if (!m_modelAvailable->initModel())
|
|
return false;
|
|
|
|
m_filterAvailable = new AvailStreamsFilter(m_modelAvailable, this);
|
|
m_modelAllocated = new AllocatedStreamsModel(this);
|
|
|
|
connect(m_modelAvailable, &AvailStreamsModel::droppedStreamNames, this, &AudioSettingsDialog::onDroppedInAvailable); // Drag and Drop from allocated -> available
|
|
connect(m_modelAllocated, &AllocatedStreamsModel::droppedStreamNames, this, &AudioSettingsDialog::onDroppedInAllocated); // Drag and Drop from available -> allocated
|
|
|
|
connect(m_modelAvailable, &AvailStreamsModel::updateEntry, m_modelAllocated, &AllocatedStreamsModel::updateEntry);
|
|
connect(m_modelAvailable, &AvailStreamsModel::removeEntry, this, &AudioSettingsDialog::onEntryRemoved);
|
|
|
|
// Glue model and view together
|
|
m_ui->treeViewAvailable->setModel(m_filterAvailable);
|
|
m_ui->treeViewAvailable->expandAll();
|
|
m_ui->treeViewAllocated->setModel(m_modelAllocated);
|
|
|
|
// Operator Management to get Name from operator
|
|
connect(opmDtc, &OperatorManagement::Interface::Dtc::userChanged,
|
|
this, &AudioSettingsDialog::onOperatorChanged);
|
|
auto cbOperator = [this](const OperatorManagement::User & u)
|
|
{
|
|
onOperatorChanged(u, DataModification::eAdded);
|
|
};
|
|
opmDtc->users(cbOperator);
|
|
|
|
fillOperatorBox();
|
|
|
|
connect(m_avmDtc, &Interface::Dtc::cnrTvcProfileChanged,
|
|
this, &AudioSettingsDialog::onCnrTvcProfileChanged);
|
|
auto cbRadioCircuits = [this](const CnrTvcProfile & rc)
|
|
{
|
|
onCnrTvcProfileChanged(rc, DataModification::eAdded);
|
|
};
|
|
m_avmDtc->cnrTvcProfiles(cbRadioCircuits);
|
|
|
|
connect(m_ui->pushButtonUp, &QPushButton::clicked, this, &AudioSettingsDialog::onUpButtonClicked);
|
|
connect(m_ui->pushButtonDown, &QPushButton::clicked, this, &AudioSettingsDialog::onDownButtonClicked);
|
|
connect(m_ui->operatorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AudioSettingsDialog::onSelectionOperatorChanged);
|
|
connect(m_ui->treeViewAllocated->selectionModel(), &QItemSelectionModel::selectionChanged, this, &AudioSettingsDialog::onSelectionChangedAllocation);
|
|
// Populate our Model
|
|
|
|
m_ui->treeViewAllocated->setSelectionMode(QAbstractItemView::MultiSelection);
|
|
m_ui->treeViewAvailable->setSelectionMode(QAbstractItemView::MultiSelection);
|
|
|
|
m_ui->treeViewAllocated->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
m_ui->treeViewAvailable->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
|
|
//m_ui->treeViewAllocated->setSortingEnabled(true);
|
|
//m_ui->treeViewAllocated->sortByColumn(0,Qt::AscendingOrder );
|
|
|
|
m_ui->pushButtonUp->setEnabled(false);
|
|
m_ui->pushButtonDown->setEnabled(false);
|
|
|
|
m_avmFtc->enableAll();
|
|
|
|
int opId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
|
|
if (m_ui->operatorComboBox->currentIndex() != m_ui->operatorComboBox->findData(opId))
|
|
m_ui->operatorComboBox->setCurrentIndex(m_ui->operatorComboBox->findData(opId));
|
|
else
|
|
onSelectionOperatorChanged(0); //param is unused
|
|
setUnchangeable(false);
|
|
return true;
|
|
} // end of init
|
|
|
|
void AudioSettingsDialog::retranslate()
|
|
{
|
|
translate(m_ui, tr("Voice Communication Access"));
|
|
} // end of retranslate
|
|
|
|
void AudioSettingsDialog::onOperatorChanged(const OperatorManagement::User &data, DataModification modType)
|
|
{
|
|
// Table: opm.opm_operator
|
|
DEBUG_LOG(m_logger) << "************** onOperatorChanged ";
|
|
switch (modType)
|
|
{
|
|
case DataModification::eRemoved:
|
|
{
|
|
Q_ASSERT(m_operatorMap.contains(data.id()));
|
|
|
|
// Check, if Operator is currently open, if yes, reset any changes
|
|
if (m_ui->operatorComboBox->currentData().toInt() == data.id())
|
|
{
|
|
__unchange__();
|
|
m_modelAllocated->resetChangeState();
|
|
m_modelAvailable->resetChangeState();
|
|
m_filterAvailable->invalidate();
|
|
}
|
|
|
|
m_operatorMap.remove(data.id());
|
|
m_ui->operatorComboBox->removeItem(m_ui->operatorComboBox->findData(data.id()));
|
|
break;
|
|
}
|
|
|
|
case DataModification::eAdded:
|
|
{
|
|
Q_ASSERT(!m_operatorMap.contains(data.id()));
|
|
const QString operatorName = QString::fromStdString(data.name());
|
|
m_operatorMap.insert(data.id(), operatorName);
|
|
m_ui->operatorComboBox->addItem(operatorName, data.id());
|
|
m_ui->operatorComboBox->model()->sort(0);
|
|
break;
|
|
}
|
|
|
|
case DataModification::eModified:
|
|
{
|
|
Q_ASSERT(m_operatorMap.contains(data.id()));
|
|
const QString operatorName = QString::fromStdString(data.name());
|
|
m_operatorMap.insert(data.id(), operatorName);
|
|
int i = m_ui->operatorComboBox->findData(data.id());
|
|
Q_ASSERT(i != -1);
|
|
m_ui->operatorComboBox->setItemText(i, operatorName);
|
|
m_ui->operatorComboBox->model()->sort(0);
|
|
break;
|
|
}
|
|
}
|
|
} // end of onOperatorChanged
|
|
|
|
void AudioSettingsDialog::onCnrTvcProfileChanged(const CnrTvcProfile &data, DataModification modType)
|
|
{
|
|
if (m_session->exerciseId() == data.exerciseId())
|
|
{
|
|
if (modType == DataModification::eRemoved)
|
|
{
|
|
m_cnrTvcProfileMap.remove(data.id());
|
|
}
|
|
else
|
|
{
|
|
m_cnrTvcProfileMap.insert(data.id(), data);
|
|
fillOperatorList();
|
|
}
|
|
}
|
|
} // end of onCnrTvcProfileChanged
|
|
|
|
void AudioSettingsDialog::fillOperatorList()
|
|
{
|
|
QVector<StreamData> newStreamData;
|
|
|
|
for (const auto &rc : qAsConst(m_cnrTvcProfileMap))
|
|
{
|
|
if ((rc.exerciseId() != m_session->exerciseId())
|
|
|| (rc.operatorId() != m_ui->operatorComboBox->currentData().toInt()))
|
|
continue;
|
|
|
|
// insert entry in Allocated
|
|
newStreamData.reserve(rc.data().size());
|
|
for (const CnrTvcProfileData &profileEntry : rc.data())
|
|
newStreamData += toStreamData(profileEntry);
|
|
|
|
break;
|
|
}
|
|
m_modelAllocated->setNewStreamData(newStreamData);
|
|
m_filterAvailable->setAllocatedStreams(newStreamData);
|
|
} // end of fillOperatorList
|
|
|
|
void AudioSettingsDialog::fillOperatorBox()
|
|
{
|
|
m_ui->operatorComboBox->clear();
|
|
QMap<int, QString>::iterator i = m_operatorMap.begin();
|
|
while (i != m_operatorMap.end())
|
|
{
|
|
m_ui->operatorComboBox->addItem(i.value(), i.key());
|
|
++i;
|
|
}
|
|
m_ui->operatorComboBox->model()->sort(0);
|
|
}
|
|
|
|
void AudioSettingsDialog::onUpButtonClicked()
|
|
{
|
|
const QModelIndexList mil = m_ui->treeViewAllocated->selectionModel()->selectedIndexes();
|
|
if (mil.isEmpty())
|
|
return;
|
|
m_modelAllocated->changeOrder(mil.first(), true);
|
|
|
|
if (mil.first().row() > 0)
|
|
{
|
|
const QModelIndex newRow = m_modelAllocated->index(mil.first().row() - 1, 0);
|
|
m_ui->treeViewAllocated->setCurrentIndex(newRow);
|
|
}
|
|
|
|
slotChangesMade();
|
|
} // end of onUpButtonClicked
|
|
|
|
void AudioSettingsDialog::onDownButtonClicked()
|
|
{
|
|
const QModelIndexList mil = m_ui->treeViewAllocated->selectionModel()->selectedIndexes();
|
|
if (mil.isEmpty())
|
|
return;
|
|
m_modelAllocated->changeOrder(mil.first(), false);
|
|
const QModelIndex newRow = m_modelAllocated->index(mil.first().row() + 1, 0);
|
|
m_ui->treeViewAllocated->setCurrentIndex(newRow);
|
|
slotChangesMade();
|
|
} // end of onDownButtonClicked
|
|
|
|
void AudioSettingsDialog::onSelectionChangedAllocation(const QItemSelection &selected, const QItemSelection &deselected)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onSelectionChangedAllocation selected.isEmpty()=" << selected.isEmpty();
|
|
Q_UNUSED(deselected);
|
|
QModelIndex first = m_ui->treeViewAllocated->model()->index(0, 0);
|
|
int rowCnt = m_ui->treeViewAllocated->model()->rowCount();
|
|
QModelIndex last = m_ui->treeViewAllocated->model()->index(rowCnt - 1, 0);
|
|
QModelIndexList selectedRows = m_ui->treeViewAllocated->selectionModel()->selectedIndexes();
|
|
const int cntSelectedRows = selectedRows.size();
|
|
if (cntSelectedRows > 1)
|
|
{
|
|
m_ui->pushButtonUp->setEnabled(false);
|
|
m_ui->pushButtonDown->setEnabled(false);
|
|
return;
|
|
}
|
|
if (selected.size() > 0)
|
|
{
|
|
m_ui->pushButtonUp->setEnabled(selected.first().indexes().first() != first);
|
|
m_ui->pushButtonDown->setEnabled(selected.first().indexes().first() != last);
|
|
}
|
|
} // end of onSelectionAllocationChanged
|
|
|
|
|
|
bool AudioSettingsDialog::apply()
|
|
{
|
|
if (m_modelAllocated->getStreamDataVector().isEmpty())
|
|
applyRemove();
|
|
else
|
|
applyModify();
|
|
m_modelAllocated->resetChangeState();
|
|
m_modelAvailable->resetChangeState();
|
|
m_filterAvailable->invalidate();
|
|
return true;
|
|
}
|
|
|
|
bool AudioSettingsDialog::applyRemove()
|
|
{
|
|
RemoveCnrTvcProfileRequest removeRequest;
|
|
DEBUG_LOG(m_logger) << "AudioSettingsDialog::applyRemove";
|
|
|
|
for (const auto &profile : qAsConst(m_cnrTvcProfileMap))
|
|
{
|
|
if (profile.operatorId() != m_operatorId)
|
|
continue;
|
|
removeRequest.id(profile.id());
|
|
break;
|
|
}
|
|
if (removeRequest.id() <= 0)
|
|
return true;
|
|
|
|
m_requestHelper->startSingleRequest([this, removeRequest]()
|
|
{
|
|
return m_avmFtc->removeCnrTvcProfileRequest(removeRequest, this);
|
|
});
|
|
|
|
return true;
|
|
} // end of applyRemove
|
|
|
|
bool AudioSettingsDialog::applyModify()
|
|
{
|
|
ModifyCnrTvcProfileRequest modifyRequest;
|
|
DEBUG_LOG(m_logger) << "AudioSettingsDialog::applyModify";
|
|
|
|
for (const auto &profile : qAsConst(m_cnrTvcProfileMap))
|
|
{
|
|
if (profile.operatorId() != m_operatorId)
|
|
continue;
|
|
modifyRequest.id(profile.id());
|
|
break;
|
|
}
|
|
|
|
modifyRequest.exerciseId(m_session->exerciseId());
|
|
modifyRequest.operatorId(m_operatorId);
|
|
|
|
const QVector<StreamData> allocatedList = m_modelAllocated->getStreamDataVector();
|
|
modifyRequest.data().reserve(allocatedList.size());
|
|
for (const StreamData &stream : allocatedList)
|
|
{
|
|
CnrTvcProfileData circuitData;
|
|
circuitData.radioSystemId(stream.bIsCnr ? RadioSystem::Cnr : RadioSystem::Tvc);
|
|
circuitData.radioCircuitId(stream.topicId);
|
|
modifyRequest.data().push_back(std::move(circuitData));
|
|
}
|
|
|
|
m_requestHelper->startSingleRequest([this, modifyRequest]()
|
|
{
|
|
return m_avmFtc->modifyCnrTvcProfileRequest(modifyRequest, this);
|
|
});
|
|
|
|
return true;
|
|
} // end of applyModify
|
|
|
|
void AudioSettingsDialog::onModifyCnrTvcProfileReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
__unchange__();
|
|
m_requestHelper->requestReply(replyObject);
|
|
} // end of onCreateRadioCircuitsReply
|
|
//-----------------------------------------------------------------------------
|
|
void AudioSettingsDialog::onRemoveCnrTvcProfileReply(const Core::FunctionReplyObject &replyObject)
|
|
{
|
|
__unchange__();
|
|
m_requestHelper->requestReply(replyObject);
|
|
} // end of onRemoveRadioCircuitsReply
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void AudioSettingsDialog::onSelectionOperatorChanged(const int index)
|
|
{
|
|
Q_UNUSED(index);
|
|
if (hasUnsavedChanges() ||
|
|
m_modelAllocated->getChangeState() ||
|
|
m_modelAvailable->getChangeState())
|
|
{
|
|
switch (askApplyDiscardCancel())
|
|
{
|
|
case LtsWidgets::Button::Apply:
|
|
if (!apply())
|
|
return;
|
|
break;
|
|
case LtsWidgets::Button::Cancel:
|
|
{
|
|
// cfroebel 2019-06-26:
|
|
// Setting back the operator would cause this slot to be called again.
|
|
// Thus we avoid this by blocking signals.
|
|
{
|
|
QSignalBlocker blockSignals(m_ui->operatorComboBox);
|
|
m_ui->operatorComboBox->setCurrentIndex(m_ui->operatorComboBox->findData(m_operatorId)); // reset position
|
|
}
|
|
return;
|
|
}
|
|
case LtsWidgets::Button::Discard:
|
|
__unchange__(); // can't call resetChanges() by myself :(
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
m_ui->pushButtonUp->setEnabled(false);
|
|
m_ui->pushButtonDown->setEnabled(false);
|
|
m_operatorId = m_ui->operatorComboBox->currentData().toInt();
|
|
DEBUG_LOG(m_logger) << "onSelectionOperatorChanged" << " operatorStr=" << m_ui->operatorComboBox->currentText() << " m_operatorId= " << m_operatorId;
|
|
fillOperatorList();
|
|
m_modelAllocated->resetChangeState();
|
|
m_modelAvailable->resetChangeState();
|
|
m_filterAvailable->invalidate();
|
|
}
|
|
|
|
void AudioSettingsDialog::onDroppedInAllocated(const QVector<StreamData> &streams)
|
|
{
|
|
slotChangesMade();
|
|
m_filterAvailable->addAllocatedStreams(streams);
|
|
m_modelAllocated->setStreamChanged(streams);
|
|
m_modelAvailable->setStreamChanged(streams);
|
|
}
|
|
|
|
void AudioSettingsDialog::onDroppedInAvailable(const QVector<StreamData> &streams)
|
|
{
|
|
slotChangesMade();
|
|
m_filterAvailable->removeAllocatedStreams(streams);
|
|
m_modelAllocated->setStreamChanged(streams);
|
|
m_modelAvailable->setStreamChanged(streams);
|
|
}
|
|
|
|
void AudioSettingsDialog::onEntryRemoved(const StreamData &stream)
|
|
{
|
|
m_modelAllocated->removeEntry(stream);
|
|
m_filterAvailable->removeAllocatedStreams({stream}); // in case the stream was allocated forget about it
|
|
}
|
|
|
|
StreamData AudioSettingsDialog::toStreamData(const CnrTvcProfileData &profileEntry) const
|
|
{
|
|
int configId = profileEntry.radioCircuitId();
|
|
StreamData streamData;
|
|
streamData.topicId = configId;
|
|
|
|
if (profileEntry.radioSystemId() == RadioSystem::Cnr)
|
|
{
|
|
streamData.name = QString::fromStdString(m_avmDtc->cnrConfig(configId).radioCircuit());
|
|
streamData.bIsCnr = true;
|
|
}
|
|
else
|
|
{
|
|
streamData.name = QString::fromStdString(m_avmDtc->tvcConfig(configId).radioCircuit());
|
|
streamData.bIsCnr = false;
|
|
}
|
|
|
|
return streamData;
|
|
}
|
|
|
|
} // namespace AudioVideoManagement
|