#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cuetracklistwidget.h" CueTrackListWidget::CueTrackListWidget(QWidget *parent) { layout = new QVBoxLayout(this); tableWidget = new QTableWidget(); tableWidget->setSortingEnabled(false); layout->addWidget(tableWidget); setLayout(layout); QShortcut *shortcut_up = new QShortcut(QKeySequence("Up"), parent); QObject::connect(shortcut_up, SIGNAL(activated()), this, SLOT(key_up())); QShortcut *shortcut_down = new QShortcut(QKeySequence("Down"), parent); QObject::connect(shortcut_down, SIGNAL(activated()), this, SLOT(key_down())); QShortcut *shortcut_copy = new QShortcut(QKeySequence("Ctrl+C"), parent); QObject::connect(shortcut_copy, SIGNAL(activated()), this, SLOT(copyCueTrack())); QShortcut *shortcut_cut = new QShortcut(QKeySequence("Ctrl+X"), parent); QObject::connect(shortcut_cut, SIGNAL(activated()), this, SLOT(cutCueTrack())); QShortcut *shortcut_paste = new QShortcut(QKeySequence("Ctrl+V"), parent); QObject::connect(shortcut_paste, SIGNAL(activated()), this, SLOT(pasteCueTrack())); tableWidget->installEventFilter(this); QShortcut *shortcut_delete = new QShortcut(QKeySequence("Delete"), parent); QObject::connect(shortcut_delete, SIGNAL(activated()), this, SLOT(deleteCueTrack())); QShortcut *shortcut_insert = new QShortcut(QKeySequence("Insert"), parent); QObject::connect(shortcut_insert, SIGNAL(activated()), this, SLOT(createNewCueTrack())); QShortcut *shortcut_edit = new QShortcut(QKeySequence("e"), parent); QObject::connect(shortcut_edit, SIGNAL(activated()), this, SLOT(editCueTrack())); } void CueTrackListWidget::addCueTrack(CueTrack* cue) { cueTracks.push_back(cue); displayCueTrackInTable(cue, -1); m_size++; } void CueTrackListWidget::removeCueTrack(int index) { if (index >= m_size) return; cueTracks.erase(cueTracks.begin() + index); tableWidget->removeRow(index); m_size--; } CueTrack* CueTrackListWidget::getTrackAtIndex(int index) { if (index < m_size) { return cueTracks.at(index); } return nullptr; } CueTrack* CueTrackListWidget::getSelectedTrack(bool advance) { CueTrack* track = getTrackAtIndex(selectedIndex); if (advance) key_down(); return track; } void CueTrackListWidget::key_up() { if (m_size > 0 && selectedIndex > 0) { updateSelectedCueTrack(false); selectedIndex--; updateSelectedCueTrack(true); tableWidget->scrollToItem(tableWidget->item(selectedIndex, 0)); } emit changeSelectedIndex(selectedIndex); } void CueTrackListWidget::key_down() { if (selectedIndex < m_size - 1 && m_size > 0) { updateSelectedCueTrack(false); selectedIndex++; updateSelectedCueTrack(true); tableWidget->scrollToItem(tableWidget->item(selectedIndex, 0)); } emit changeSelectedIndex(selectedIndex); } void CueTrackListWidget::displayCueTrackInTable(CueTrack *cueTrack, int index) { if (tableWidget->columnCount() == 0) { tableWidget->setColumnCount(7); QStringList headers = {"Active", "Number","Audio Channel", "Name", "Volume", "Status", "File"}; tableWidget->setHorizontalHeaderLabels(headers); } if (index == -1) index = tableWidget->rowCount(); tableWidget->insertRow(index); tableWidget->setItem(index, 0, new QTableWidgetItem(cueTrack->active ? "Yes" : "No")); tableWidget->setItem(index, 1, new QTableWidgetItem(QStringLiteral("%1").arg(cueTrack->userNumber, 3, 10, QLatin1Char('0')))); tableWidget->setItem(index, 2, new QTableWidgetItem(QString::number(cueTrack->audioLayer))); tableWidget->setItem(index, 3, new QTableWidgetItem(cueTrack->name.data())); tableWidget->setItem(index, 4, new QTableWidgetItem(QString::number(cueTrack->volume))); QString statusStr; statusStr = statusToString(cueTrack->status); tableWidget->setItem(index, 5, new QTableWidgetItem(statusStr)); tableWidget->setItem(index, 6, new QTableWidgetItem(*getFileName(cueTrack->filePath))); } void CueTrackListWidget::updateSelectedCueTrack(bool highlightRow) { if (selectedIndex >= 0 && selectedIndex < tableWidget->rowCount()) { QBrush backgroundBrush(highlightRow ? QColor(248, 248, 200) : Qt::white); for (int column = 0; column < tableWidget->columnCount(); ++column) { QTableWidgetItem *item = tableWidget->item(selectedIndex, column); if (!item) { item = new QTableWidgetItem(); tableWidget->setItem(selectedIndex, column, item); } item->setBackground(backgroundBrush); } tableWidget->resizeColumnsToContents(); tableWidget->resizeRowsToContents(); } } void CueTrackListWidget::cueTrackLoadDefaults(CueTrack * t) { t->active = false; t->audioLayer = 0; t->bus1 = 100; t->bus2 = 100; t->entryPoint = 0; t->exitPoint = 255; t->fadeIn = 2; t->fadeOut = 2; t->waitIn = 0; t->waitOut = 0; t->pan = 0; t->pitch = 1; t->status = Status::PlayingOnce; lastUserCueNumber += 10; t->userNumber = lastUserCueNumber; t->volume = 80; t->stopAtEnd = true; t->filePath = ""; t->duration = 0; t->multi = false; } void CueTrackListWidget::createNewCueTrack() { CueTrack *t = new CueTrack; cueTrackLoadDefaults(t); EditCueTrackWidget dialog(t, this); if (dialog.exec() == QDialog::Accepted) { t->active = false; addCueTrack(t); if (m_size == 1) { updateSelectedCueTrack(true); emit changeSelectedIndex(0); } else redrawCueTrackList(); if (lastUserCueNumber < t->userNumber) lastUserCueNumber = t->userNumber; } else delete (t); } void CueTrackListWidget::editCueTrack() { CueTrack *current = getTrackAtIndex(selectedIndex); EditCueTrackWidget dialog(current, this); if (dialog.exec() == QDialog::Accepted) { copyCueTrack(dialog.cueTrack, current); redrawCueTrackList(); emit changeSelectedIndex(selectedIndex); } if (lastUserCueNumber < current->userNumber) lastUserCueNumber = current->userNumber; } void CueTrackListWidget::deleteCueTrack() { QMessageBox::StandardButton reply; reply = QMessageBox::question(this, "Delete Cue Track", "Are you sure you want to delete this cue track?", QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::Yes) { removeCueTrack(selectedIndex); if (selectedIndex >= m_size) { selectedIndex = m_size - 1; emit changeSelectedIndex(selectedIndex); } redrawCueTrackList(); } } void CueTrackListWidget::copyCueTrack(CueTrack *src, CueTrack *dst) { dst->active = src->active; dst->audioLayer = src->audioLayer; dst->bus1 = src->bus1; dst->bus2 = src->bus2; dst->entryPoint = src->entryPoint; dst->exitPoint = src->exitPoint; dst->fadeIn = src->fadeIn; dst->fadeOut = src->fadeOut; dst->waitIn = src->waitIn; dst->waitOut = src->waitOut; dst->pan = src->pan; dst->pitch = src->pitch; dst->status = src->status; dst->userNumber = src->userNumber; dst->volume = src->volume; dst->stopAtEnd = src->stopAtEnd; dst->name = src->name; dst->description = src->description; dst->filePath = src->filePath; dst->duration = src->duration; dst->multi = src->multi; } QString *CueTrackListWidget::getFileName(std::string s) { size_t bar = s.rfind("/"); std::string tmp = s.substr(bar + 1, strlen(s.data())); QString *ret = new QString(tmp.data()); ret->truncate(64); return ret; } void CueTrackListWidget::sortCueTrackList() { std::sort(cueTracks.begin(), cueTracks.end(), [](CueTrack *a, CueTrack *b) { return a->userNumber < b->userNumber; }); } void CueTrackListWidget::redrawCueTrackList() { if (!m_size) return; int selected = cueTracks.at(selectedIndex)->userNumber; clearTableWidget(); tableWidget->setColumnCount(7); QStringList headers = {"Active", "Number","Channel", "Name", "Volume", "Status", "File"}; tableWidget->setHorizontalHeaderLabels(headers); sortCueTrackList(); selectedIndex = 0; for (int i = 0; i < m_size; i++) { displayCueTrackInTable(cueTracks.at(i), i); } selectedIndex = 0; while (cueTracks.at(selectedIndex)->userNumber != selected) { selectedIndex++; } updateSelectedCueTrack(true); tableWidget->resizeColumnsToContents(); tableWidget->resizeRowsToContents(); tableWidget->scrollToItem(tableWidget->item(selectedIndex, 0)); tableWidget->blockSignals(false); emit changeSelectedIndex(selectedIndex); } void CueTrackListWidget::loadCueTrackList(std::string filename) { qDebug() << "loading cue list from " << filename.data(); QFile file(QString::fromStdString(filename)); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { std::cerr << "No se pudo abrir el archivo para lectura" << std::endl; return; } QXmlStreamReader xmlReader(&file); clearCueTrackList(); lastUserCueNumber = 0; while (!xmlReader.atEnd() && !xmlReader.hasError()) { QXmlStreamReader::TokenType token = xmlReader.readNext(); if (token == QXmlStreamReader::StartElement) { if (xmlReader.name() == "CueTrack") { CueTrack *t = new CueTrack; while (!(xmlReader.tokenType() == QXmlStreamReader::EndElement && xmlReader.name() == "CueTrack")) { if (xmlReader.tokenType() == QXmlStreamReader::StartElement) { QString elementName = xmlReader.name().toString(); xmlReader.readNext(); if (xmlReader.tokenType() == QXmlStreamReader::Characters) { if (elementName == "filePath") { t->filePath = xmlReader.text().toString().toStdString(); } else if (elementName == "volume") { t->volume = xmlReader.text().toInt(); } else if (elementName == "pan") { t->pan = xmlReader.text().toInt(); } else if (elementName == "pitch") { t->pitch = xmlReader.text().toInt(); } else if (elementName == "bus1") { t->bus1 = xmlReader.text().toInt(); } else if (elementName == "bus2") { t->bus2 = xmlReader.text().toInt(); } else if (elementName == "status") { QString tmp = xmlReader.text().toString(); t->status = stringToStatus(&tmp); } else if (elementName == "fadeOut") { t->fadeOut = xmlReader.text().toInt(); } else if (elementName == "fadeIn") { t->fadeIn = xmlReader.text().toInt(); } else if (elementName == "waitIn") { t->waitIn = xmlReader.text().toInt(); } else if (elementName == "waitOut") { t->waitOut = xmlReader.text().toInt(); } else if (elementName == "stopAtEnd") { QString tmp = xmlReader.text().toString().toLower(); if (tmp.compare("false")) t->stopAtEnd = true; else { t->stopAtEnd = false; } } else if (elementName == "name") { t->name = xmlReader.text().toString().toStdString(); } else if (elementName == "description") { t->description = xmlReader.text().toString().toStdString(); } else if (elementName == "userNumber") { t->userNumber = xmlReader.text().toInt(); if (t->userNumber > lastUserCueNumber) { lastUserCueNumber = t->userNumber; } } else if (elementName == "entryPoint") { t->entryPoint = xmlReader.text().toInt(); } else if (elementName == "exitPoint") { t->exitPoint = xmlReader.text().toInt(); } else if (elementName == "audioLayer") { t->audioLayer = xmlReader.text().toInt(); } else if (elementName == "duration") { t->duration = xmlReader.text().toInt(); } else if (elementName == "multi") { QString tmp = xmlReader.text().toString().toLower(); if (tmp.compare("false")) t->multi = true; else { t->multi = false; } } t->active = false; } } xmlReader.readNext(); } addCueTrack(t); } } } if (xmlReader.hasError()) { std::cerr << "Error al leer el archivo XML: " << xmlReader.errorString().toStdString() << std::endl; } file.close(); redrawCueTrackList(); } void CueTrackListWidget::saveCueTrackList(std::string filename) { qDebug() << "saving cue list to " << filename.data(); std::ofstream file(filename); if (!file.is_open()) { return; } file << "\n"; file << "\n"; for (int i = 0; i < m_size; i++) { file << cueTrackToXml(*cueTracks.at(i)) << std::endl; } file << "\n"; file.close(); } std::string CueTrackListWidget::cueTrackToXml(const CueTrack& cueTrack) { std::string xml = " \n"; xml += " " + cueTrack.filePath + "\n"; xml += " " + std::to_string(cueTrack.volume) + "\n"; xml += " " + std::to_string(cueTrack.pan) + "\n"; xml += " " + std::to_string(cueTrack.pitch) + "\n"; xml += " " + std::to_string(cueTrack.bus1) + "\n"; xml += " " + std::to_string(cueTrack.bus2) + "\n"; xml += " "; xml += statusToString(cueTrack.status); xml += "\n"; xml += " " + std::to_string(cueTrack.fadeOut) + "\n"; xml += " " + std::to_string(cueTrack.fadeIn) + "\n"; xml += " " + std::to_string(cueTrack.waitIn) + "\n"; xml += " " + std::to_string(cueTrack.waitOut) + "\n"; xml += " "; xml += (cueTrack.stopAtEnd ? "true" : "false"); xml += "\n"; xml += " " + cueTrack.name + "\n"; xml += " " + cueTrack.description + "\n"; xml += " " + std::to_string(cueTrack.userNumber) + "\n"; xml += " " + std::to_string(cueTrack.entryPoint) + "\n"; xml += " " + std::to_string(cueTrack.exitPoint) + "\n"; xml += " " + std::to_string(cueTrack.audioLayer) + "\n"; xml += " " + std::to_string(cueTrack.duration) + "\n"; xml += " "; xml += (cueTrack.multi ? "true" : "false"); xml += "\n"; xml += " \n"; return xml; } void CueTrackListWidget::clearCueTrackList() { for (int i = 0; i < m_size; i++) { delete cueTracks.at(i); } cueTracks.clear(); m_size = 0; selectedIndex = 0; } #include #include void saveCueTrackToXml(const CueTrack& cueTrack, const QString& filename) { QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { qInfo() << "Can not open file " << filename << "\n"; return; } QXmlStreamWriter xmlWriter(&file); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument(); xmlWriter.writeStartElement("CueTrack"); xmlWriter.writeTextElement("filePath", QString::fromStdString(cueTrack.filePath)); xmlWriter.writeTextElement("volume", QString::number(cueTrack.volume)); xmlWriter.writeTextElement("pan", QString::number(cueTrack.pan)); xmlWriter.writeTextElement("pitch", QString::number(cueTrack.pitch)); xmlWriter.writeTextElement("bus1", QString::number(cueTrack.bus1)); xmlWriter.writeTextElement("bus2", QString::number(cueTrack.bus2)); xmlWriter.writeTextElement("status", statusToString(cueTrack.status)); xmlWriter.writeTextElement("fadeOut", QString::number(cueTrack.fadeOut)); xmlWriter.writeTextElement("fadeIn", QString::number(cueTrack.fadeIn)); xmlWriter.writeTextElement("waitIn", QString::number(cueTrack.waitIn)); xmlWriter.writeTextElement("waitOut", QString::number(cueTrack.waitOut)); xmlWriter.writeTextElement("stopAtEnd", cueTrack.stopAtEnd ? "true" : "false"); xmlWriter.writeTextElement("name", QString::fromStdString(cueTrack.name)); xmlWriter.writeTextElement("description", QString::fromStdString(cueTrack.description)); xmlWriter.writeTextElement("userNumber", QString::number(cueTrack.userNumber)); xmlWriter.writeTextElement("entryPoint", QString::number(cueTrack.entryPoint)); xmlWriter.writeTextElement("exitPoint", QString::number(cueTrack.exitPoint)); xmlWriter.writeTextElement("audioLayer", QString::number(cueTrack.audioLayer)); xmlWriter.writeEndElement(); xmlWriter.writeEndDocument(); file.close(); } #include #include #include #include CueTrack loadCueTrackFromXml(const QString& filename) { QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { throw std::runtime_error("No se pudo abrir el archivo"); } QXmlStreamReader xmlReader(&file); CueTrack cueTrack; while (!xmlReader.atEnd() && !xmlReader.hasError()) { QXmlStreamReader::TokenType token = xmlReader.readNext(); if (token == QXmlStreamReader::StartElement) { const QString elementName = xmlReader.name().toString(); if (elementName == "filePath") { cueTrack.filePath = xmlReader.readElementText().toStdString(); } else if (elementName == "volume") { cueTrack.volume = xmlReader.readElementText().toInt(); } else if (elementName == "pan") { cueTrack.pan = xmlReader.readElementText().toInt(); } else if (elementName == "pitch") { cueTrack.pitch = xmlReader.readElementText().toInt(); } else if (elementName == "bus1") { cueTrack.bus1 = xmlReader.readElementText().toInt(); } else if (elementName == "bus2") { cueTrack.bus2 = xmlReader.readElementText().toInt(); } else if (elementName == "status") { QString tmp = xmlReader.readElementText(); cueTrack.status = stringToStatus(&tmp); } else if (elementName == "fadeOut") { cueTrack.fadeOut = xmlReader.readElementText().toInt(); } else if (elementName == "fadeIn") { cueTrack.fadeIn = xmlReader.readElementText().toInt(); } else if (elementName == "waitIn") { cueTrack.waitIn = xmlReader.readElementText().toInt(); } else if (elementName == "waitOut") { cueTrack.waitOut = xmlReader.readElementText().toInt(); } else if (elementName == "stopAtEnd") { cueTrack.stopAtEnd = xmlReader.readElementText() == "true"; } else if (elementName == "name") { cueTrack.name = xmlReader.readElementText().toStdString(); } else if (elementName == "description") { cueTrack.description = xmlReader.readElementText().toStdString(); } else if (elementName == "userNumber") { cueTrack.userNumber = xmlReader.readElementText().toInt(); } else if (elementName == "entryPoint") { cueTrack.entryPoint = xmlReader.readElementText().toInt(); } else if (elementName == "exitPoint") { cueTrack.exitPoint = xmlReader.readElementText().toInt(); } else if (elementName == "audioLayer") { cueTrack.audioLayer = xmlReader.readElementText().toInt(); } else if (elementName == "duration") { cueTrack.duration = xmlReader.readElementText().toInt(); } } } if (xmlReader.hasError()) { throw std::runtime_error("Error al parsear el archivo XML"); } file.close(); return cueTrack; } void CueTrackListWidget::clearTableWidget() { for (int i = 0; i < m_size; i++) { tableWidget->removeRow(i); } tableWidget->clear(); tableWidget->setRowCount(0); } void CueTrackListWidget::cueTrackAtEnd(int layer) { for (int i = 0; i < m_size; i++) { CueTrack * cur = cueTracks.at(i); if (cur->audioLayer == layer) { cur->active = false; } } redrawCueTrackList(); } void CueTrackListWidget::copyCueTrack() { if (selectedIndex >= 0 && selectedIndex < m_size) { delete copiedCue; copiedCue = new CueTrack(*cueTracks.at(selectedIndex)); } } void CueTrackListWidget::cutCueTrack() { if (selectedIndex >= 0 && selectedIndex < m_size) { delete copiedCue; copiedCue = new CueTrack(*cueTracks.at(selectedIndex)); removeCueTrack(selectedIndex); } } void CueTrackListWidget::pasteCueTrack() { if (copiedCue != nullptr) { CueTrack* newCue = new CueTrack(*copiedCue); addCueTrack(newCue); } }