File indexing completed on 2025-02-23 04:34:23

0001 /**
0002  * \file formatlistedit.cpp
0003  * Widget to edit a format list.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 13 Aug 2011
0008  *
0009  * Copyright (C) 2011-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #include "formatlistedit.h"
0028 #include <QPushButton>
0029 #include <QLineEdit>
0030 #include <QComboBox>
0031 #include <QLayout>
0032 #include <QFormLayout>
0033 #include <QSizePolicy>
0034 
0035 /**
0036  * Constructor.
0037  *
0038  * @param labels list of label texts for fields in a single format
0039  * @param tooltips list of tooltips, one string per label, empty if not used
0040  * @param parent parent widget
0041  */
0042 FormatListEdit::FormatListEdit(const QStringList& labels,
0043                                const QStringList& tooltips,
0044                                QWidget* parent)
0045   : QWidget(parent)
0046 {
0047   setObjectName(QLatin1String("FormatListEdit"));
0048   auto hlayout = new QHBoxLayout(this);
0049   hlayout->setContentsMargins(0, 0, 0, 0);
0050   auto formatLayout = new QFormLayout;
0051   formatLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
0052   bool comboBoxCreated = false;
0053   for (int i = 0; i < labels.size(); ++i) {
0054     const QString& label = labels.at(i);
0055     const QString& toolTip = tooltips.at(i);
0056     if (!comboBoxCreated) {
0057       m_formatComboBox = new QComboBox;
0058       m_formatComboBox->setEditable(true);
0059       m_formatComboBox->setInsertPolicy(QComboBox::NoInsert);
0060       connect(m_formatComboBox, static_cast<void (QComboBox::*)(int)>(
0061                 &QComboBox::activated),
0062               this, &FormatListEdit::updateLineEdits);
0063       connect(m_formatComboBox->lineEdit(), &QLineEdit::editingFinished,
0064               this, &FormatListEdit::commitCurrentEdits);
0065       if (!toolTip.isEmpty())
0066         m_formatComboBox->setToolTip(toolTip);
0067       formatLayout->addRow(label, m_formatComboBox);
0068       comboBoxCreated = true;
0069     } else {
0070       auto ed = new QLineEdit;
0071       connect(ed, &QLineEdit::returnPressed, this, &FormatListEdit::formatChanged);
0072       if (!toolTip.isEmpty())
0073         ed->setToolTip(toolTip);
0074       formatLayout->addRow(label, ed);
0075       m_lineEdits.append(ed); // clazy:exclude=reserve-candidates
0076     }
0077   }
0078   hlayout->addLayout(formatLayout);
0079   auto vlayout = new QVBoxLayout;
0080 #ifdef Q_OS_MAC
0081   vlayout->setSpacing(6);
0082 #endif
0083   m_addPushButton = new QPushButton(tr("&Add"));
0084   m_addPushButton->setAutoDefault(false);
0085   m_removePushButton = new QPushButton(tr("&Remove"));
0086   m_removePushButton->setAutoDefault(false);
0087   vlayout->addWidget(m_addPushButton);
0088   vlayout->addWidget(m_removePushButton);
0089   vlayout->addStretch();
0090   hlayout->addLayout(vlayout);
0091   connect(m_addPushButton, &QAbstractButton::clicked, this, &FormatListEdit::addItem);
0092   connect(m_removePushButton, &QAbstractButton::clicked, this, &FormatListEdit::removeItem);
0093   setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
0094 }
0095 
0096 /**
0097  * Set format strings.
0098  *
0099  * @param formats list of format stringlists, the first stringlist contains
0100  *   the names, the second the corresponding string for the first line edit,
0101  *   etc.
0102  * @param index index to select, -1 to keep current index
0103  */
0104 void FormatListEdit::setFormats(const QList<QStringList>& formats, int index)
0105 {
0106   m_formats = formats;
0107   if (index >= 0) {
0108     m_formatComboBox->setCurrentIndex(index);
0109     updateComboBoxAndLineEdits(index);
0110   }
0111 }
0112 
0113 /**
0114  * Get format strings.
0115  *
0116  * @param index  if not null, the current index is returned here
0117  *
0118  * @return list of format stringlists, the first stringlist contains
0119  *   the names, the second the corresponding string for the first line edit,
0120  *   etc.
0121  */
0122 QList<QStringList> FormatListEdit::getFormats(int* index)
0123 {
0124   commitCurrentEdits();
0125   if (index) {
0126     *index = m_formatComboBox->currentIndex();
0127   }
0128   return m_formats;
0129 }
0130 
0131 /**
0132  * Get a format string from the format currently displayed in the GUI.
0133  *
0134  * @param formatNr index of the format stringlist, 0 is the format name
0135  *   1 the first line edit, etc.
0136  *
0137  * @return format string.
0138  */
0139 QString FormatListEdit::getCurrentFormat(int formatNr) const
0140 {
0141   if (formatNr == 0) {
0142     return m_formatComboBox->currentText();
0143   }
0144   if (formatNr > 0 && formatNr - 1 < m_lineEdits.size()) {
0145     return m_lineEdits.at(formatNr - 1)->text();
0146   }
0147   return QString();
0148 }
0149 
0150 /**
0151  * Update GUI controls from formats.
0152  *
0153  * @param index combo box index to set
0154  */
0155 void FormatListEdit::updateComboBoxAndLineEdits(int index)
0156 {
0157   m_formatComboBox->clear();
0158   if (!m_formats.isEmpty()) {
0159 #if QT_VERSION >= 0x050600
0160     const QStringList& firstFormat = m_formats.constFirst();
0161 #else
0162     const QStringList& firstFormat = m_formats.first();
0163 #endif
0164     m_formatComboBox->addItems(firstFormat);
0165     if (index >= 0 && index < firstFormat.size()) {
0166       m_formatComboBox->setCurrentIndex(index);
0167       updateLineEdits(index);
0168     }
0169   }
0170 }
0171 
0172 /**
0173  * Set the currently selected format from the contents of the controls.
0174  */
0175 void FormatListEdit::commitCurrentEdits()
0176 {
0177   int index = m_formatComboBox->currentIndex();
0178   if (index < 0)
0179     return;
0180 
0181   if (m_formatComboBox->itemText(index) != m_formatComboBox->currentText()) {
0182     m_formatComboBox->setItemText(index,  m_formatComboBox->currentText());
0183   }
0184 
0185   for (int i = 0; i < m_formats.size() && i - 1 < m_lineEdits.size(); ++i) {
0186     QString text(i == 0
0187                  ? m_formatComboBox->currentText()
0188                  : m_lineEdits.at(i - 1)->text());
0189     if (QStringList& fmts = m_formats[i]; index < fmts.size()) { // clazy:exclude=detaching-member
0190       fmts[index] = text;
0191     }
0192   }
0193 }
0194 
0195 /**
0196  * Set the format lineedits to the format of the index.
0197  *
0198  * @param index selected item in combo box
0199  */
0200 void FormatListEdit::updateLineEdits(int index)
0201 {
0202   for (int i = 0; i < m_lineEdits.size() && i + 1 < m_formats.size(); ++i) {
0203     QLineEdit* le = m_lineEdits.at(i);
0204     if (const QStringList& fmts = m_formats.at(i + 1); index < fmts.size()) {
0205       le->setText(fmts.at(index));
0206     } else {
0207       le->clear();
0208     }
0209   }
0210   emit formatChanged();
0211 }
0212 
0213 /**
0214  * Add a new item.
0215  */
0216 void FormatListEdit::addItem()
0217 {
0218   commitCurrentEdits();
0219   if (!m_formats.isEmpty()) {
0220     // first search for an existing empty format
0221     int index = -1;
0222 #if QT_VERSION >= 0x050600
0223     for (int fmtIdx = m_formats.constFirst().size() - 1; fmtIdx > 0; --fmtIdx)
0224 #else
0225     for (int fmtIdx = m_formats.first().size() - 1; fmtIdx > 0; --fmtIdx)
0226 #endif
0227     {
0228       bool allEmpty = true;
0229       for (int leIdx = 1; leIdx < m_formats.size(); ++leIdx) {
0230         if (const QStringList& fmts = m_formats.at(leIdx);
0231             fmtIdx < fmts.size() && !fmts.at(fmtIdx).isEmpty()) {
0232           allEmpty = false;
0233           break;
0234         }
0235       }
0236       if (allEmpty) {
0237         index = fmtIdx;
0238         break;
0239       }
0240     }
0241 
0242     if (index == -1) {
0243       // no empty format found, add a new one
0244       for (int i = 0; i < m_formats.size(); ++i) {
0245         m_formats[i].append(i == 0 ? tr("New") : QLatin1String(""));
0246       }
0247 #if QT_VERSION >= 0x050600
0248       index = m_formats.constFirst().size() - 1;
0249 #else
0250       index = m_formats.first().size() - 1;
0251 #endif
0252     }
0253     updateComboBoxAndLineEdits(index);
0254     m_formatComboBox->lineEdit()->setFocus();
0255     m_formatComboBox->lineEdit()->selectAll();
0256   }
0257 }
0258 
0259 /**
0260  * Remove the selected item.
0261  */
0262 void FormatListEdit::removeItem()
0263 {
0264   int index = m_formatComboBox->currentIndex();
0265   if (index < 0)
0266     return;
0267 
0268   for (int i = 0; i < m_formats.size(); ++i) {
0269     if (index < m_formats.at(i).size()) {
0270       m_formats[i].removeAt(index);
0271     }
0272   }
0273   if (!m_formats.isEmpty()) {
0274 #if QT_VERSION >= 0x050600
0275     const QStringList& fmts = m_formats.constFirst();
0276 #else
0277     const QStringList& fmts = m_formats.first();
0278 #endif
0279     if (index >= fmts.size()) {
0280       index = fmts.size() - 1;
0281     }
0282     if (index < 0) {
0283       addItem();
0284     } else {
0285       updateComboBoxAndLineEdits(index);
0286     }
0287   }
0288 }