#include "tagpanel.h" #include #include #include #include TagPanel::TagPanel(const QString &tag, QWidget *parent) : QGroupBox(QStringLiteral("[%1]").arg(tag), parent) , m_tag(tag) { auto *layout = new QVBoxLayout(this); layout->setContentsMargins(6, 14, 6, 6); layout->setSpacing(4); m_table = new QTableWidget(0, 2, this); m_table->setHorizontalHeaderLabels({tr("Key"), tr("Value")}); m_table->horizontalHeader()->setStretchLastSection(true); m_table->verticalHeader()->hide(); m_table->setEditTriggers(QAbstractItemView::NoEditTriggers); m_table->setAlternatingRowColors(true); m_table->setMaximumHeight(220); m_table->verticalHeader()->setDefaultSectionSize(22); layout->addWidget(m_table); m_rawLabel = new QLabel(this); m_rawLabel->setWordWrap(true); m_rawLabel->setStyleSheet("font-family: monospace;"); m_rawLabel->hide(); layout->addWidget(m_rawLabel); auto *btnRow = new QHBoxLayout(); btnRow->addStretch(); auto *copyBtn = new QPushButton(tr("📋 Copy"), this); copyBtn->setToolTip(tr("Copy current tag values to clipboard")); copyBtn->setMaximumWidth(90); connect(copyBtn, &QPushButton::clicked, this, &TagPanel::copyToClipboard); btnRow->addWidget(copyBtn); layout->addLayout(btnRow); } void TagPanel::update(const QString &value) { static const QRegularExpression kvRe(R"((\w+)=(\S+))"); if (kvRe.match(value).hasMatch()) { parseKeyValue(value); m_rawLabel->hide(); m_table->show(); } else { showRaw(value); m_table->hide(); m_rawLabel->show(); } } void TagPanel::parseKeyValue(const QString &value) { static const QRegularExpression kvRe(R"((\w+)=(\S+))"); auto it = kvRe.globalMatch(value); while (it.hasNext()) { const auto match = it.next(); const QString key = match.captured(1); const QString raw = match.captured(2); // Split on ';' -> list of values. A plain (non-list) value yields // a QStringList with exactly one element, which still goes through // the same code path for consistency. QStringList values = raw.split(';', Qt::SkipEmptyParts); if (values.isEmpty()) values << raw; // preserve even an empty/odd value as-is setKeyValues(key, values); } } void TagPanel::setKeyValues(const QString &key, const QStringList &values) { const int newCount = values.size(); if (m_keyRanges.contains(key)) { // Key already exists – remove its current rows, then re-insert at // the same starting position with the new row count. const KeyRange old = m_keyRanges[key]; for (int i = 0; i < old.count; ++i) m_table->removeRow(old.firstRow); // Shift all OTHER key ranges that started after this one for (auto it = m_keyRanges.begin(); it != m_keyRanges.end(); ++it) { if (it.key() != key && it->firstRow > old.firstRow) it->firstRow += (newCount - old.count); } int insertAt = old.firstRow; for (int i = 0; i < newCount; ++i) { m_table->insertRow(insertAt + i); auto *keyItem = new QTableWidgetItem(i == 0 ? key : QString()); auto *valItem = new QTableWidgetItem(values[i]); valItem->setBackground(QColor(0x2d, 0x5a, 0x2d)); // flash green on update m_table->setItem(insertAt + i, 0, keyItem); m_table->setItem(insertAt + i, 1, valItem); } m_keyRanges[key] = {insertAt, newCount}; } else { // New key – append at the bottom const int insertAt = m_table->rowCount(); for (int i = 0; i < newCount; ++i) { m_table->insertRow(insertAt + i); auto *keyItem = new QTableWidgetItem(i == 0 ? key : QString()); auto *valItem = new QTableWidgetItem(values[i]); valItem->setBackground(QColor(0x2d, 0x5a, 0x2d)); m_table->setItem(insertAt + i, 0, keyItem); m_table->setItem(insertAt + i, 1, valItem); } m_keyRanges[key] = {insertAt, newCount}; } } void TagPanel::showRaw(const QString &value) { m_rawLabel->setText(value); } void TagPanel::copyToClipboard() { QStringList lines; lines << QStringLiteral("[%1]").arg(m_tag); if (m_table->isVisible()) { QString lastKey; for (int r = 0; r < m_table->rowCount(); ++r) { const QString key = m_table->item(r, 0)->text(); const QString val = m_table->item(r, 1)->text(); if (!key.isEmpty()) { lines << QStringLiteral(" %1 = %2").arg(key, val); lastKey = key; } else { lines << QStringLiteral(" %1").arg(val); // continuation row } } } else { lines << QStringLiteral(" %1").arg(m_rawLabel->text()); } QApplication::clipboard()->setText(lines.join('\n')); }