/** * @RDE_HEADER@ * * TableView for dynamic topics * * $Id$ * $HeadURL$ * $Author$ */ #include "sampleview.h" #include "samplemodel.h" #include "topicselector.h" #include "detailviewdlg.h" #include #include #include #include #include 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(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 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 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 &data, const QString &topicName) { DetailViewDlg *dlg = qobject_cast(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); }