Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

@@ -0,0 +1,297 @@
/**
* @RDE_HEADER@
* OperatorManangement - Show all available streams
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-11-06
*/
#include "audio_settings_avail_streams_model.h"
#include <nglwidgets/ngltreeitem.h>
#include <QFont>
namespace AudioVideoManagement
{
QDataStream &operator<<(QDataStream &ds, const StreamData &sd)
{
ds << sd.topicId << sd.name << sd.bIsCnr;
return ds;
}
QDataStream &operator>>(QDataStream &ds, StreamData &sd)
{
ds >> sd.topicId >> sd.name >> sd.bIsCnr ;
return ds;
}
//
// AvailStreamsModel
//
AvailStreamsModel::AvailStreamsModel(Interface::Dtc *avmDtc,
int32_t exerciseId,
QObject *parent)
: NGLTreeModel(parent, new NGLTreeItem(QVariant()), {tr("Available")})
, m_exerciseId(exerciseId)
, m_avmDtc(avmDtc)
, m_cnrRoot(new NGLTreeItem(QVariant()))
, m_tvcRoot(new NGLTreeItem(QVariant()))
, m_changes(false)
, m_logger(getLogger("AudioSettingsAvailStreamsModel"))
{
Q_ASSERT(avmDtc);
qRegisterMetaTypeStreamOperators<StreamData>();
setMimeType(StreamData::mimeType());
StreamData data;
data.name = tr("CNR");
data.bIsCnr = true;
m_cnrRoot->setData(QVariant::fromValue(data));
m_rootItem->appendChild(m_cnrRoot);
data.name = tr("TVC");
data.bIsCnr = false;
m_tvcRoot->setData(QVariant::fromValue(data));
m_rootItem->appendChild(m_tvcRoot);
}
/*
AvailStreamsModel::~AvailStreamsModel()
{
// do not delete, is deleted through root item
//delete m_cnrRoot;
//delete m_tvcRoot;
}
*/
void AvailStreamsModel::setStreamChanged(const QVector<StreamData> &streams)
{
for (const StreamData &d : streams)
if (!m_changedStreams.contains(QPair<bool,int>(d.bIsCnr, d.topicId)))
m_changedStreams += QPair<bool,int>(d.bIsCnr, d.topicId);
emit modelDataChanged();
}
bool AvailStreamsModel::initModel()
{
connect(m_avmDtc, &AudioVideoManagement::Interface::Dtc::cnrConfigChanged,
this, &AvailStreamsModel::onCnrConfigChanged, Qt::UniqueConnection);
m_avmDtc->cnrConfigs([this](const AudioVideoManagement::CnrConfig & ch) { onCnrConfigChanged(ch, DataModification::eAdded); });
#if 0
AudioVideoManagement::CnrConfig data;
data.exerciseId(42);
data.id(1);
data.radioCircuit(QStringLiteral("test1").toStdString());
onCnrConfigChanged(data, DataModification::eAdded);
data.id(2);
data.radioCircuit(QStringLiteral("test2").toStdString());
onCnrConfigChanged(data, DataModification::eAdded);
AudioVideoManagement::TvcConfig data2;
data2.id(1);
data2.radioCircuit(QStringLiteral("test3 (tvc)").toStdString());
onTvcConfigChanged(data2, DataModification::eAdded);
#endif
connect(m_avmDtc, &AudioVideoManagement::Interface::Dtc::tvcConfigChanged,
this, &AvailStreamsModel::onTvcConfigChanged, Qt::UniqueConnection);
m_avmDtc->tvcConfigs([this](const AudioVideoManagement::TvcConfig & ch) { onTvcConfigChanged(ch, DataModification::eAdded); });
return true;
}
Qt::ItemFlags AvailStreamsModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags f = NGLTreeModel::flags(index) | Qt::ItemIsDropEnabled;
if (!index.parent().isValid())
f &= ~Qt::ItemIsDragEnabled;
return f;
}
QVariant AvailStreamsModel::data(const QModelIndex &index, int role) const
{
switch (role)
{
case Qt::DisplayRole:
{
NGLTreeItem *item = privateData(index);
StreamData data = item->data().value<StreamData>();
DEBUG_LOG(m_logger) << data.name;
return data.name;
}
case Qt::FontRole:
{
NGLTreeItem *item = privateData(index);
StreamData data = item->data().value<StreamData>();
if (!m_changedStreams.contains(QPair<bool,int>(data.bIsCnr, data.topicId)))
return {};
QFont f;
f.setBold(true);
return f;
}
default:
{
break;
}
}
return NGLTreeModel::data(index, role);
}
bool AvailStreamsModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(data);
Q_UNUSED(row);
Q_UNUSED(column);
Q_UNUSED(parent);
if (action != supportedDropActions())
return false;
return true;
}
bool AvailStreamsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent)
{
Q_UNUSED(action);
Q_UNUSED(row);
Q_UNUSED(column);
Q_UNUSED(parent);
const QVector<NGLTreeItem *> droppedItems = getMimeDataItems(data, m_mimeType);
QVector<StreamData> streams;
streams.reserve(droppedItems.size());
for (const NGLTreeItem *item : droppedItems)
streams += item->data().value<StreamData>();
qDeleteAll(droppedItems);
emit droppedStreamNames(streams);
m_changes = true;
return true;
}
void AvailStreamsModel::onCnrConfigChanged(const AudioVideoManagement::CnrConfig &data, DataModification modType)
{
insertUpdateData(data, modType, m_cnrRoot);
}
void AvailStreamsModel::onTvcConfigChanged(const AudioVideoManagement::TvcConfig &data, DataModification modType)
{
insertUpdateData(data, modType, m_tvcRoot);
}
template <typename T>
void AvailStreamsModel::insertUpdateData(const T &config, DataModification modType, NGLTreeItem *parent)
{
DataModification action = modType;
if (modType == DataModification::eModified)
{
// If a config of a different Exercise was changed the config might have been global before.
// Thus we might need to remove this config.
if (config.exerciseId().is_set() && config.exerciseId().get() != m_exerciseId)
action = DataModification::eRemoved;
}
StreamData newData(config);
switch (action)
{
case DataModification::eAdded:
if (config.exerciseId().is_set() && config.exerciseId().get() != m_exerciseId)
break;
Q_FALLTHROUGH();
case DataModification::eModified:
{
bool bFound = false;
for (int i = 0; i < parent->childCount(); ++i)
{
NGLTreeItem *child = parent->child(i);
StreamData data = child->data().value<StreamData>();
if (data == newData)
{
bFound = true;
setItemData(indexFromItem(child), QVariant::fromValue(newData), child->icon());
emit updateEntry(newData);
break;
}
}
if (!bFound)
{
NGLTreeItem *child = new NGLTreeItem(QVariant::fromValue(newData));
insertRow(parent->childCount(), indexFromItem(parent), child);
}
break;
}
case DataModification::eRemoved:
{
for (int i = 0; i < parent->childCount(); ++i)
{
NGLTreeItem *child = parent->child(i);
StreamData data = child->data().value<StreamData>();
if (data == newData)
{
removeRows(i, 1, indexFromItem(parent));
emit removeEntry(newData);
break;
}
}
}
}
}
//
// AvailStreamsFilter
//
AvailStreamsFilter::AvailStreamsFilter(AvailStreamsModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
, m_sourceModel(sourceModel)
{
Q_ASSERT(sourceModel);
setSourceModel(m_sourceModel);
}
void AvailStreamsFilter::addAllocatedStreams(const QVector<StreamData> &streams)
{
m_allocatedStreams.insert(streams.begin(), streams.end());
invalidateFilter();
}
void AvailStreamsFilter::setAllocatedStreams(const QVector<StreamData> &streams)
{
m_allocatedStreams.clear();
m_allocatedStreams.insert(streams.begin(), streams.end());
invalidateFilter();
}
void AvailStreamsFilter::removeAllocatedStreams(const QVector<StreamData> &streams)
{
for (const StreamData &stream : streams)
m_allocatedStreams.erase(stream);
invalidateFilter();
}
bool AvailStreamsFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!m_sourceModel || !source_parent.isValid())
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
NGLTreeItem *parent = m_sourceModel->privateData(source_parent);
if (!parent)
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
NGLTreeItem *child = parent->child(source_row);
if (!child)
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
StreamData data = child->data().value<StreamData>();
return m_allocatedStreams.count(data) == 0;
}
} // namespace AudioVideoManagement
@@ -0,0 +1,88 @@
/**
* @RDE_HEADER@
* OperatorManangement - Show all available streams
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-11-06
*/
#pragma once
#include <nglwidgets/ngltreemodel.h>
#include <AudioVideoManagement/avm_dtc.h>
#include <AudioVideoManagement/logger.h>
#include <QSortFilterProxyModel>
#include <QVector>
#include "audio_stream_type.h"
#include <set>
#include <utility>
namespace AudioVideoManagement
{
class AvailStreamsModel final : public NGLTreeModel
{
Q_OBJECT
public:
explicit AvailStreamsModel(AudioVideoManagement::Interface::Dtc *avmDtc, int32_t exerciseId,
QObject *parent = nullptr);
~AvailStreamsModel() = default;
bool getChangeState() {bool result = m_changes; m_changes = false; return result;}
void resetChangeState() {m_changes = false;m_changedStreams.clear();}
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant data(const QModelIndex &index, int role) const override;
// CopyAction - data is filtered with proxy model
Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; }
Qt::DropActions supportedDragActions() const override { return Qt::CopyAction; }
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override;
bool dropMimeData(const QMimeData *data, Qt::DropAction, int, int, const QModelIndex &) override;
void setStreamChanged(const QVector<StreamData> &streams);
bool initModel();
signals:
void droppedStreamNames(const QVector<AudioVideoManagement::StreamData> &streamNamesDropped);
void updateEntry(const AudioVideoManagement::StreamData &stream);
void removeEntry(const AudioVideoManagement::StreamData &stream);
private slots:
void onCnrConfigChanged(const AudioVideoManagement::CnrConfig &data, DataModification modType);
void onTvcConfigChanged(const AudioVideoManagement::TvcConfig &data, DataModification modType);
private:
template <typename T>
void insertUpdateData(const T &data, DataModification modType, NGLTreeItem *parent);
int32_t m_exerciseId;
AudioVideoManagement::Interface::Dtc *m_avmDtc;
NGLTreeItem *m_cnrRoot;
NGLTreeItem *m_tvcRoot;
bool m_changes;
QVector<QPair<bool /* is cnr */, int> > m_changedStreams;
NGL::INGLLogger &m_logger;
};
class AvailStreamsFilter final : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit AvailStreamsFilter(AvailStreamsModel *sourceModel, QObject *parent);
void addAllocatedStreams(const QVector<StreamData> &streams);
void setAllocatedStreams(const QVector<StreamData> &streams);
void removeAllocatedStreams(const QVector<StreamData> &streams);
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
private:
/** Don't use directly; will we done via constructor. */
using QSortFilterProxyModel::setSourceModel;
AvailStreamsModel *m_sourceModel;
std::set<StreamData> m_allocatedStreams;
};
} // namespace AudioVideoManagement
@@ -0,0 +1,440 @@
/**
* @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
@@ -0,0 +1,108 @@
/**
* @RDE_HEADER@
* OperatorManangement - Operator Edit Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2016-02-29
*/
#pragma once
#include <OperatorManagement/opm_dtc.h>
#include <AudioVideoManagement/avm_dtc.h>
#include <AudioVideoManagement/logger.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <AudioVideoManagement/avm_ftc.h>
#include <QVector>
#include <QMap>
#include <QString>
namespace Ui
{
class AudioSettingsDialog;
}
namespace LtsSession
{
class LtsSessionDataDds;
}
class QItemSelection;
namespace AudioVideoManagement
{
struct StreamData;
class AvailStreamsModel;
class AvailStreamsFilter;
class AllocatedStreamsModel;
class AudioSettingsDialog : public LtsWidgets::LtsDialog
, protected AudioVideoManagement::Interface::Ftc::ModifyCnrTvcProfileReplyHandler
, protected AudioVideoManagement::Interface::Ftc::RemoveCnrTvcProfileReplyHandler
{
Q_OBJECT
public:
explicit AudioSettingsDialog(QWidget *parent = nullptr);
~AudioSettingsDialog();
bool init(OperatorManagement::Interface::Dtc *opmDtc,
AudioVideoManagement::Interface::Dtc *avmDtc,
AudioVideoManagement::Interface::Ftc *avmFtc,
LtsSession::LtsSessionDataDds *session);
void onModifyCnrTvcProfileReply(const Core::FunctionReplyObject &replyObject) override;
void onRemoveCnrTvcProfileReply(const Core::FunctionReplyObject &replyObject) override;
private:
enum class CircuitChoice
{
None,
Cnr,
Tvc
};
void retranslate() override;
bool apply() override final;
bool applyModify();
bool applyRemove();
void fillOperatorBox();
void fillOperatorList();
private slots:
void onOperatorChanged(const OperatorManagement::User &data, DataModification modType);
void onCnrTvcProfileChanged(const AudioVideoManagement::CnrTvcProfile &data, DataModification modType);
void onUpButtonClicked();
void onDownButtonClicked();
void onSelectionChangedAllocation(const QItemSelection &selected, const QItemSelection &deselected);
void onSelectionOperatorChanged(const int index);
void onDroppedInAllocated(const QVector<StreamData> &streams);
void onDroppedInAvailable(const QVector<StreamData> &streams);
void onEntryRemoved(const StreamData &stream);
private:
StreamData toStreamData(const CnrTvcProfileData &profileEntry) const;
AudioVideoManagement::Interface::Dtc *m_avmDtc{nullptr};
AudioVideoManagement::Interface::Ftc *m_avmFtc{nullptr};
int m_operatorId{-1}; //!< currently displayed operator
QMap<int, QString> m_operatorMap;
QMap<int, AudioVideoManagement::CnrTvcProfile> m_cnrTvcProfileMap; // all dds-Configs key = DDS-ID
AvailStreamsModel *m_modelAvailable{nullptr};
AvailStreamsFilter *m_filterAvailable{nullptr};
AllocatedStreamsModel *m_modelAllocated{nullptr};
Ui::AudioSettingsDialog *m_ui{nullptr};
LtsUtils::RequestHelper *m_requestHelper{nullptr};
LtsSession::LtsSessionDataDds *m_session{nullptr};
LOGGER_T m_logger;
};
}
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AudioSettingsDialog</class>
<widget class="QWidget" name="AudioSettingsDialog">
<property name="windowTitle">
<string>Voice Communication Access</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" rowspan="5">
<widget class="QTreeView" name="treeViewAvailable">
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="5">
<widget class="QTreeView" name="treeViewAllocated">
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::CopyAction</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
<attribute name="headerCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
</widget>
</item>
<item row="1" column="2">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>90</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonUp">
<property name="text">
<string notr="true">↑ </string>
</property>
</widget>
</item>
<item row="3" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="2">
<widget class="QPushButton" name="pushButtonDown">
<property name="text">
<string notr="true">↓</string>
</property>
</widget>
</item>
<item row="5" column="2">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>89</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="3">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lbxOperator">
<property name="text">
<string>Operator:</string>
</property>
</widget>
</item>
<item>
<widget class="LtsWidgets::LtsComboBox" name="operatorComboBox">
<property name="const" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>operatorComboBox</tabstop>
<tabstop>treeViewAvailable</tabstop>
<tabstop>treeViewAllocated</tabstop>
<tabstop>pushButtonUp</tabstop>
<tabstop>pushButtonDown</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,186 @@
/**
* @RDE_HEADER@
* OperatorManangement - Show all available streams
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-11-06
*/
#include "audio_settings_used_streams_model.h"
#include <nglwidgets/ngltreeitem.h>
#include <QMimeData>
#include <QFont>
namespace AudioVideoManagement
{
//
// UsedStreamsModel
//
AllocatedStreamsModel::AllocatedStreamsModel(QObject *parent)
: NGLTreeModel(parent, new NGLTreeItem(QVariant(QLatin1String("root"))), { tr("Allocated") })
, m_logger(getLogger("AudioSettingsUsedStreamsModel"))
{
setMimeType(StreamData::mimeType());
}
Qt::ItemFlags AllocatedStreamsModel::flags(const QModelIndex &index) const
{
return NGLTreeModel::flags(index) | Qt::ItemIsDropEnabled;
}
QVariant AllocatedStreamsModel::data(const QModelIndex &index, int role) const
{
switch (role)
{
case Qt::DisplayRole:
{
NGLTreeItem *item = privateData(index);
StreamData data = item->data().value<StreamData>();
DEBUG_LOG(m_logger) << data.name;
return data.name;
}
case Qt::FontRole:
{
NGLTreeItem *item = privateData(index);
StreamData data = item->data().value<StreamData>();
if (!m_changedStreams.contains(QPair<bool,int>(data.bIsCnr, data.topicId)))
return {};
QFont f;
f.setBold(true);
return f;
}
default:
{
break;
}
}
return NGLTreeModel::data(index, role);
}
void AllocatedStreamsModel::setStreamChanged(const QVector<StreamData> &streams)
{
for (const StreamData &d : streams)
if (!m_changedStreams.contains(QPair<bool,int>(d.bIsCnr, d.topicId)))
m_changedStreams += QPair<bool,int>(d.bIsCnr, d.topicId);
emit modelDataChanged();
}
bool AllocatedStreamsModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(data);
Q_UNUSED(row);
Q_UNUSED(column);
Q_UNUSED(parent);
if (action != supportedDropActions())
return false;
return true;
}
bool AllocatedStreamsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent)
{
Q_UNUSED(row);
Q_UNUSED(column);
Q_UNUSED(parent);
const QVector<NGLTreeItem *> droppedItems = getMimeDataItems(data, m_mimeType);
QVector<StreamData> streams;
streams.reserve(droppedItems.size());
for (const NGLTreeItem *item : droppedItems)
streams += item->data().value<StreamData>();
qDeleteAll(droppedItems);
emit droppedStreamNames(streams);
m_changes = true;
DEBUG_LOG(m_logger) << data->data(QStringLiteral("NGLTreeModel/dragDrop"));
return NGLTreeModel::dropMimeData(data, action, row, 0, QModelIndex());
}
void AllocatedStreamsModel::setNewStreamData(const QVector<StreamData> &newData)
{
DEBUG_LOG(m_logger) << "set new stream data, count: " << newData.size();
resetModel();
for (const StreamData &sd : newData)
m_rootItem->appendChild(new NGLTreeItem(QVariant::fromValue(sd)));
emit modelDataChanged();
}
QVector<StreamData> AllocatedStreamsModel::getStreamDataVector() const
{
QVector<StreamData> result;
result.reserve(m_rootItem->childCount());
for (int i = 0; i < m_rootItem->childCount(); i++)
{
const NGLTreeItem *item = m_rootItem->child(i);
const StreamData sd = item->data().value<StreamData>();
result.append(sd);
DEBUG_LOG(m_logger) << "result.append(sd.name):" << sd.name;
}
DEBUG_LOG(m_logger) << "getStreamDataVector() size: " << result.size();
return result;
}
void AllocatedStreamsModel::changeOrder(const QModelIndex &idx, bool up)
{
DEBUG_LOG(m_logger) << "changeOrder "
<< " index = " << idx.row()
<< " up = " << up
<< " m_rootItem->childCount()= " << m_rootItem->childCount();
if (up)
{
moveRow(idx.parent(), idx.row(),
idx.parent(), idx.row() - 1);
}
else
{
moveRow(idx.parent(), idx.row(),
idx.parent(), idx.row() + 1);
}
emit modelDataChanged();
}
// Wird ueber connect im SettingsDialog vom AvailableModel::updateEntry aufgerufen
void AllocatedStreamsModel::updateEntry(const StreamData &stream)
{
for (int i = 0; i < m_rootItem->childCount(); i++)
{
NGLTreeItem *child = m_rootItem->child(i);
StreamData data = child->data().value<StreamData>();
if (data == stream)
{
setItemData(indexFromItem(child), QVariant::fromValue(stream), child->icon());
break;
}
}
emit modelDataChanged();
}
// Wird ueber connect im SettingsDialog vom AvailableModel::removeEntry aufgerufen
void AllocatedStreamsModel::removeEntry(const StreamData &stream)
{
for (int i = 0; i < m_rootItem->childCount(); i++)
{
NGLTreeItem *child = m_rootItem->child(i);
StreamData data = child->data().value<StreamData>();
if (data == stream)
{
removeRows(i, 1, indexFromItem(m_rootItem));
break;
}
}
emit modelDataChanged();
}
} // namespace AudioVideoManagement
@@ -0,0 +1,54 @@
/**
* @RDE_HEADER@
* OperatorManangement - Show all available streams
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-11-06
*/
#pragma once
#include <nglwidgets/ngltreemodel.h>
#include <AudioVideoManagement/logger.h>
#include "audio_stream_type.h"
namespace AudioVideoManagement
{
class AllocatedStreamsModel final : public NGLTreeModel
{
Q_OBJECT
public:
explicit AllocatedStreamsModel(QObject *parent = nullptr);
bool getChangeState() {bool result = m_changes; m_changes = false; return result;}
void resetChangeState() {m_changes = false;m_changedStreams.clear();}
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Qt::DropActions supportedDropActions() const override { return Qt::CopyAction; }
Qt::DropActions supportedDragActions() const override { return Qt::MoveAction; }
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override;
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) override;
void setStreamChanged(const QVector<StreamData> &streams);
void setNewStreamData(const QVector<StreamData> &newData);
QVector<StreamData> getStreamDataVector() const;
void changeOrder(const QModelIndex &idx, bool up);
void updateEntry(const StreamData &stream);
void removeEntry(const StreamData &stream);
signals:
void droppedStreamNames(const QVector<AudioVideoManagement::StreamData> &streamNamesDropped);
private:
bool m_changes{false};
QVector<QPair<bool /* is cnr */, int> > m_changedStreams;
NGL::INGLLogger &m_logger;
};
} // namespace AudioVideoManagement
@@ -0,0 +1,56 @@
/**
* @RDE_HEADER@
* OperatorManangement - Show all available streams
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-11-06
*/
#pragma once
#include <AudioVideoManagement/avm.hpp>
#include <QString>
#include <QObject>
#include <boost/operators.hpp>
#include <utility>
namespace AudioVideoManagement
{
/**
* Helper struct used by AvailStreamsModel, AllocatedStreamsModel.
*
* Comparision operators only consider bIsCnr and topicId, i.e. name is irrelevant.
*/
struct StreamData : boost::totally_ordered<StreamData>
{
StreamData() = default;
explicit StreamData(const TvcConfig &tvcConfig)
: name(QString::fromStdString(tvcConfig.radioCircuit()))
, topicId(tvcConfig.id())
, bIsCnr(false)
{}
explicit StreamData(const CnrConfig &cnrConfig)
: name(QString::fromStdString(cnrConfig.radioCircuit()))
, topicId(cnrConfig.id())
, bIsCnr(true)
{}
QString name;
int topicId = 0;
bool bIsCnr = false;
static QString mimeType() { return QStringLiteral("AVM/StreamData"); }
bool operator<(const StreamData &other) const { return asPair() < other.asPair(); }
bool operator==(const StreamData &other) const { return asPair() == other.asPair(); }
private:
std::pair<bool, int> asPair() const { return {bIsCnr, topicId}; }
};
} // namespace AudioVideoManagement
Q_DECLARE_METATYPE(AudioVideoManagement::StreamData);