355 lines
9.9 KiB
C++
Executable File
355 lines
9.9 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
*
|
|
* TableView for dynamic topics
|
|
*
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#include "sampleview.h"
|
|
#include "samplemodel.h"
|
|
|
|
#include "topicselector.h"
|
|
#include "detailviewdlg.h"
|
|
|
|
#include <QHeaderView>
|
|
#include <QMenu>
|
|
#include <QFile>
|
|
#include <QFileDialog>
|
|
#include <QMessageBox>
|
|
|
|
SampleView::SampleView(QWidget *parent)
|
|
: QTableView(parent)
|
|
, m_proxyModel(new SampleSortModel(this))
|
|
, m_model(new SampleModel(this))
|
|
, m_topicSelector(nullptr)
|
|
, m_playTimer(this)
|
|
, m_repeat(false)
|
|
, m_bConnected(false)
|
|
, m_logger(DdsView::getLogger("SampleView"))
|
|
{
|
|
init();
|
|
}
|
|
|
|
void SampleView::init()
|
|
{
|
|
m_proxyModel->setSourceModel(m_model);
|
|
setModel(m_proxyModel);
|
|
sortByColumn(0, Qt::AscendingOrder);
|
|
|
|
setSelectionBehavior(SelectRows);
|
|
setSelectionMode(QAbstractItemView::SingleSelection);
|
|
setSortingEnabled(true);
|
|
horizontalHeader()->setStretchLastSection(true);
|
|
setAcceptDrops(true);
|
|
setDragEnabled(true);
|
|
setDragDropMode(QAbstractItemView::DragDrop);
|
|
setDropIndicatorShown(true);
|
|
setDefaultDropAction(Qt::MoveAction);
|
|
setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
|
// verticalHeader()->hide();
|
|
|
|
connect(this, &SampleView::doubleClicked, this, &SampleView::onTableDoubleClicked);
|
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
|
connect(this, &SampleView::customContextMenuRequested, this, &SampleView::onCustomContextMenuRequested);
|
|
|
|
connect(&m_playTimer, &QTimer::timeout, this, [this]() { onPlayTimerTimeout(); });
|
|
m_playTimer.setSingleShot(true);
|
|
// Todo: Model vs. ProxyModel? Column always correct?
|
|
hideColumn(static_cast<int>(SampleModel::Column::TypeName));
|
|
}
|
|
|
|
SampleView::~SampleView()
|
|
{
|
|
delete m_model;
|
|
delete m_proxyModel;
|
|
}
|
|
|
|
int SampleView::currentRow() const
|
|
{
|
|
return m_proxyModel->currentRow();
|
|
}
|
|
|
|
void SampleView::setCurrentRow(int row)
|
|
{
|
|
m_proxyModel->setCurrentRow(row);
|
|
}
|
|
|
|
void SampleView::onLoadSampleList()
|
|
{
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Load Sample List"), QString(), tr("Sample List Files (*.spl);;All Files(*)"));
|
|
|
|
if (filename.isEmpty())
|
|
return;
|
|
|
|
QFile f(filename);
|
|
if (!f.open(QFile::ReadOnly))
|
|
{
|
|
QMessageBox::warning(this, tr("File not readable"), tr("The selected file is not readable"));
|
|
return;
|
|
}
|
|
QDomDocument doc;
|
|
if (!doc.setContent(&f))
|
|
{
|
|
QMessageBox::warning(this, tr("File not readable"), tr("The selected file is no valid XML"));
|
|
f.close();
|
|
return;
|
|
}
|
|
f.close();
|
|
|
|
m_model->onClear();
|
|
|
|
QDomElement de = doc.documentElement();
|
|
if (de.nodeName() != QLatin1String("Samples"))
|
|
{
|
|
QMessageBox::warning(this, tr("File not readable"), tr("The XML file has no valid Root Item."));
|
|
return;
|
|
}
|
|
QDomNodeList dnl = de.childNodes();
|
|
int errCount = 0;
|
|
for (int i = 0; i < dnl.size(); ++i)
|
|
{
|
|
QDomNode dn = dnl.at(i);
|
|
if (!dn.isElement())
|
|
continue;
|
|
QDomElement innerDe = dn.toElement();
|
|
if (innerDe.nodeName() != QLatin1String("Sample"))
|
|
continue;
|
|
SampleModel::SampleData sample;
|
|
bool succ = sample.fromXml(innerDe);
|
|
if (succ)
|
|
m_model->addRow(sample);
|
|
else
|
|
++errCount;
|
|
}
|
|
if (errCount > 0)
|
|
QMessageBox::warning(this,
|
|
tr("Not all samples could be read"),
|
|
tr("There were %1 samples that could not be read from file.").arg(errCount));
|
|
}
|
|
|
|
void SampleView::onSaveSampleList()
|
|
{
|
|
QString selectedFilter;
|
|
QString filename = QFileDialog::getSaveFileName(this, tr("Save Sample List"), QString(),
|
|
tr("Sample List Files (*.spl);;All Files(*)"),
|
|
&selectedFilter);
|
|
if (filename.isEmpty())
|
|
return;
|
|
|
|
if (selectedFilter.contains(QLatin1String("spl")) && !filename.endsWith(QLatin1String(".spl")))
|
|
filename += QLatin1String(".spl");
|
|
|
|
QFile f(filename);
|
|
if (!f.open(QFile::WriteOnly))
|
|
return;
|
|
QDomDocument doc(QLatin1String("Samples"));
|
|
QDomElement root = doc.createElement(QLatin1String("Samples"));
|
|
doc.appendChild(root);
|
|
for (int i = 0; i < m_proxyModel->rowCount(); ++i)
|
|
{
|
|
QModelIndex mi = m_proxyModel->index(i, 0);
|
|
QModelIndex sourceMi = m_proxyModel->mapToSource(mi);
|
|
SampleModel::SampleData sample = m_model->sampleData(sourceMi);
|
|
sample.toXml(doc, root);
|
|
}
|
|
f.write(doc.toByteArray());
|
|
f.close();
|
|
}
|
|
|
|
void SampleView::onTableDoubleClicked(const QModelIndex &mi)
|
|
{
|
|
QModelIndex sourceMi = m_proxyModel->mapToSource(mi);
|
|
if (mi.column() == SampleModel::Column::Description ||
|
|
mi.column() == SampleModel::Column::Pause)
|
|
return;
|
|
|
|
const QSharedPointer<dds::core::xtypes::DynamicData> data = m_model->sampleData(sourceMi).legatusData;
|
|
|
|
DetailViewDlg *dvd = m_model->sampleData(sourceMi).dialog;
|
|
if (dvd)
|
|
{
|
|
dvd->fill(*data.data());
|
|
dvd->setWindowTitle(QString::fromLatin1("%1 (%2)").arg(m_model->sampleData(sourceMi).description,
|
|
m_model->sampleData(sourceMi).topicName));
|
|
|
|
}
|
|
else
|
|
{
|
|
dvd = new DetailViewDlg(this);
|
|
connect(dvd, &DetailViewDlg::dataChanged, this, &SampleView::onUpdateData);
|
|
connect(dvd, &DetailViewDlg::send, this, &SampleView::send);
|
|
dvd->init(*data.data(), m_model->sampleData(sourceMi).topicName, RwMode::WriteOnly);
|
|
dvd->setBtnsSendOkCancel();
|
|
dvd->setWindowTitle(QString::fromLatin1("%1 (%2)").arg(m_model->sampleData(sourceMi).description,
|
|
m_model->sampleData(sourceMi).topicName));
|
|
m_model->setDialog(sourceMi, dvd);
|
|
}
|
|
dvd->setConnected(m_bConnected);
|
|
dvd->show();
|
|
dvd->adjustSize();
|
|
}
|
|
|
|
void SampleView::onSendSample(const QModelIndex &mi)
|
|
{
|
|
const QSharedPointer<dds::core::xtypes::DynamicData> data = m_model->sampleData(m_proxyModel->mapToSource(mi)).legatusData;
|
|
emit dataClicked(*data.data());
|
|
}
|
|
|
|
void SampleView::onCustomContextMenuRequested(const QPoint &p)
|
|
{
|
|
const auto selIndexes = selectionModel()->selectedRows();
|
|
|
|
QMenu menu(this);
|
|
|
|
menu.addAction(tr("New"), this, &SampleView::onNewTopicRequested);
|
|
// Only allowg, when a row is selected
|
|
if (selIndexes.count() == 1)
|
|
menu.addAction(tr("Delete"), this, &SampleView::onDeleteIndex);
|
|
if (selIndexes.size() == 1)
|
|
menu.addAction(tr("Copy"), this, &SampleView::onCopyTelegram);
|
|
if (!m_copiedSampleData.topicName.isEmpty())
|
|
menu.addAction(tr("Paste"), this, &SampleView::onPasteTelegram);
|
|
if (m_model->rowCount() != 0)
|
|
menu.addAction(tr("Clear"), m_model, &SampleModel::onClear);
|
|
|
|
// Only allow, when a row is selected:
|
|
if (selIndexes.count() != 0 && m_bConnected)
|
|
menu.addAction(tr("Send"), this, &SampleView::onSendIndex);
|
|
|
|
// Only allow, when a row is selected:
|
|
if (selIndexes.size() == 1)
|
|
menu.addAction(tr("Set current"), this, &SampleView::onSetCurrent);
|
|
|
|
menu.addSeparator();
|
|
|
|
// Only allow saving all, when at least one row is available
|
|
if (m_model->rowCount() != 0)
|
|
menu.addAction(tr("Save all"), this, &SampleView::onSaveSampleList);
|
|
|
|
menu.addAction(tr("Load"), this, &SampleView::onLoadSampleList);
|
|
|
|
menu.exec(this->viewport()->mapToGlobal(p));
|
|
}
|
|
|
|
void SampleView::onNewTopicRequested()
|
|
{
|
|
if (!m_topicSelector)
|
|
{
|
|
m_topicSelector = new TopicSelector(TopicSelector::Usage::SampleSkeletons, this);
|
|
connect(m_topicSelector, &TopicSelector::data, this, &SampleView::onAdd);
|
|
}
|
|
m_topicSelector->show();
|
|
}
|
|
|
|
void SampleView::onAdd(const dds::core::xtypes::DynamicData &data, const QString &topicName)
|
|
{
|
|
m_model->addRow(data, topicName);
|
|
for (int i = 0; i < m_model->columnCount(QModelIndex()); ++i)
|
|
resizeColumnToContents(i);
|
|
}
|
|
|
|
void SampleView::onCopyTelegram()
|
|
{
|
|
const auto selIndexes = selectedIndexes();
|
|
if (selIndexes.isEmpty())
|
|
return;
|
|
QModelIndex sourceMi = m_proxyModel->mapToSource(selIndexes.value(0));
|
|
m_copiedSampleData = m_model->sampleData(sourceMi);
|
|
}
|
|
|
|
void SampleView::onPasteTelegram()
|
|
{
|
|
if (m_copiedSampleData.topicName.isEmpty())
|
|
return;
|
|
m_model->addRow(m_copiedSampleData);
|
|
}
|
|
|
|
void SampleView::onDeleteIndex()
|
|
{
|
|
QModelIndex sourceMi = m_proxyModel->mapToSource(selectedIndexes().value(0));
|
|
m_model->deleteRow(sourceMi);
|
|
}
|
|
|
|
void SampleView::onSendIndex()
|
|
{
|
|
const auto selIndexes = selectedIndexes();
|
|
if (selIndexes.isEmpty())
|
|
return;
|
|
QModelIndex sourceMi = m_proxyModel->mapToSource(selIndexes.value(0));
|
|
const SampleModel::SampleData sampleData = m_model->sampleData(sourceMi);
|
|
emit send(sampleData.legatusData, sampleData.topicName);
|
|
}
|
|
|
|
void SampleView::onUpdateData(const QSharedPointer<dds::core::xtypes::DynamicData> &data,
|
|
const QString &topicName)
|
|
{
|
|
DetailViewDlg *dlg = qobject_cast<DetailViewDlg *>(sender());
|
|
if (!dlg)
|
|
return;
|
|
|
|
QModelIndex index = m_model->indexByDialog(dlg);
|
|
if (index.isValid())
|
|
m_model->updateRow(index, data, topicName);
|
|
|
|
}
|
|
|
|
void SampleView::onSetCurrent()
|
|
{
|
|
QModelIndex mi = selectedIndexes().value(0);
|
|
m_proxyModel->setCurrentRow(mi.row());
|
|
verticalHeader()->resizeSections(QHeaderView::ResizeToContents);
|
|
}
|
|
|
|
void SampleView::onPlayChecked(bool down)
|
|
{
|
|
// Unchecked
|
|
if (!down)
|
|
{
|
|
m_playTimer.stop();
|
|
return;
|
|
}
|
|
|
|
// If no valid row, start from first row
|
|
if (currentRow() < 0)
|
|
setCurrentRow(0);
|
|
|
|
onPlayTimerTimeout(false);
|
|
}
|
|
|
|
void SampleView::onPlayTimerTimeout(bool moveOn)
|
|
{
|
|
// Move to next row
|
|
if (moveOn)
|
|
{
|
|
setCurrentRow(currentRow() + 1);
|
|
// If moved beyond end
|
|
if (currentRow() < 0)
|
|
{
|
|
// start over
|
|
if (m_repeat)
|
|
setCurrentRow(0);
|
|
else
|
|
{
|
|
// or stop
|
|
emit playerActive(false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
const SampleModel::SampleData sampleData = m_model->sampleData(m_proxyModel->mapToSource(m_proxyModel->index(currentRow(), 0)));
|
|
if (sampleData.legatusData)
|
|
emit send(sampleData.legatusData, sampleData.topicName);
|
|
|
|
int pause = m_model->sampleData(m_proxyModel->index(currentRow(), 0)).pause;
|
|
|
|
if (pause > 0)
|
|
m_playTimer.start(pause);
|
|
else
|
|
emit playerActive(false);
|
|
}
|
|
|