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

0001 /**
0002  * \file rendirdialog.cpp
0003  * Rename directory dialog.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 21 Mar 2004
0008  *
0009  * Copyright (C) 2004-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 "rendirdialog.h"
0028 #include <QLayout>
0029 #include <QPushButton>
0030 #include <QComboBox>
0031 #include <QLabel>
0032 #include <QDir>
0033 #include <QApplication>
0034 #include <QTextEdit>
0035 #include <QCursor>
0036 #include <QVBoxLayout>
0037 #include <QFormLayout>
0038 #include "taggedfile.h"
0039 #include "frame.h"
0040 #include "trackdata.h"
0041 #include "contexthelp.h"
0042 #include "rendirconfig.h"
0043 #include "dirrenamer.h"
0044 #include "stringlisteditdialog.h"
0045 
0046 /**
0047  * Constructor.
0048  *
0049  * @param parent parent widget
0050  * @param dirRenamer directory renamer
0051  */
0052 RenDirDialog::RenDirDialog(QWidget* parent, DirRenamer* dirRenamer)
0053   : QWizard(parent), m_taggedFile(nullptr), m_dirRenamer(dirRenamer)
0054 {
0055   setObjectName(QLatin1String("RenDirDialog"));
0056   setModal(true);
0057   setWindowTitle(tr("Rename Folder"));
0058   setSizeGripEnabled(true);
0059 #ifdef Q_OS_WIN32
0060   // The default on Windows with Qt 6.5.1 has a strange looking black rectangle
0061   // with a left arrow at the top left of the wizard dialog.
0062   setWizardStyle(ModernStyle);
0063 #endif
0064 
0065   auto mainPage = new QWizardPage;
0066 
0067   auto mainLayout = new QVBoxLayout(mainPage);
0068   setupMainPage(mainPage, mainLayout);
0069   mainPage->setTitle(tr("Format"));
0070   addPage(mainPage);
0071 
0072   auto previewPage = new QWizardPage;
0073   setupPreviewPage(previewPage);
0074   previewPage->setTitle(tr("Preview"));
0075   addPage(previewPage);
0076 
0077   setOptions(HaveHelpButton | HaveCustomButton1);
0078   setButtonText(CustomButton1, tr("&Save Settings"));
0079   connect(this, &QWizard::helpRequested, this, &RenDirDialog::showHelp);
0080   connect(this, &QWizard::customButtonClicked, this, &RenDirDialog::saveConfig);
0081   connect(this, &QWizard::currentIdChanged, this, &RenDirDialog::pageChanged);
0082 }
0083 
0084 /**
0085  * Set up the main wizard page.
0086  *
0087  * @param page    widget
0088  * @param vlayout layout
0089  */
0090 void RenDirDialog::setupMainPage(QWidget* page, QVBoxLayout* vlayout)
0091 {
0092   if (!page || !vlayout) {
0093     return;
0094   }
0095 
0096   auto actionLayout = new QFormLayout;
0097   actionLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
0098   m_actionComboBox = new QComboBox(page);
0099   m_tagversionComboBox = new QComboBox(page);
0100   m_actionComboBox->insertItem(ActionRename, tr("Rename Folder"));
0101   m_actionComboBox->insertItem(ActionCreate, tr("Create Folder"));
0102   actionLayout->addRow(tr("&Action:"), m_actionComboBox);
0103   connect(m_actionComboBox, static_cast<void (QComboBox::*)(int)>(
0104             &QComboBox::activated), this, &RenDirDialog::slotUpdateNewDirname);
0105   const QList<QPair<Frame::TagVersion, QString> > tagVersions =
0106       Frame::availableTagVersions();
0107   for (auto it = tagVersions.constBegin(); it != tagVersions.constEnd(); ++it) {
0108     m_tagversionComboBox->addItem(it->second, it->first);
0109   }
0110   actionLayout->addRow(tr("&Source:"), m_tagversionComboBox);
0111   connect(m_tagversionComboBox, static_cast<void (QComboBox::*)(int)>(
0112             &QComboBox::activated), this, &RenDirDialog::slotUpdateNewDirname);
0113 
0114   auto formatLayout = new QHBoxLayout;
0115   m_formatComboBox = new QComboBox(page);
0116   m_formatComboBox->setEditable(true);
0117   const RenDirConfig& renDirCfg = RenDirConfig::instance();
0118   m_formats = renDirCfg.dirFormats();
0119   m_format = renDirCfg.dirFormat();
0120   setFormats();
0121   formatLayout->addWidget(m_formatComboBox, 1);
0122   auto editFormatsButton = new QPushButton(tr("&Edit..."));
0123   connect(editFormatsButton, &QPushButton::clicked,
0124           this, &RenDirDialog::editFormats);
0125   formatLayout->addWidget(editFormatsButton);
0126   auto formatLabel = new QLabel(tr("&Format:"));
0127   formatLabel->setBuddy(m_formatComboBox);
0128   actionLayout->addRow(formatLabel, formatLayout);
0129   m_tagversionComboBox->setCurrentIndex(
0130         m_tagversionComboBox->findData(renDirCfg.renDirSource()));
0131   connect(m_formatComboBox, static_cast<void (QComboBox::*)(int)>(
0132             &QComboBox::activated), this, &RenDirDialog::slotUpdateNewDirname);
0133   connect(m_formatComboBox, &QComboBox::editTextChanged,
0134           this, &RenDirDialog::slotUpdateNewDirname);
0135 
0136   m_currentDirLabel = new QLabel(page);
0137   m_newDirLabel = new QLabel(page);
0138   actionLayout->addRow(tr("From:"), m_currentDirLabel);
0139   actionLayout->addRow(tr("To:"), m_newDirLabel);
0140 
0141   vlayout->addLayout(actionLayout);
0142 
0143   if (QByteArray geometry = renDirCfg.windowGeometry(); !geometry.isEmpty()) {
0144     restoreGeometry(geometry);
0145   }
0146 }
0147 
0148 /**
0149  * Set up the preview wizard page.
0150  *
0151  * @param page widget
0152  */
0153 void RenDirDialog::setupPreviewPage(QWidget* page)
0154 {
0155   auto vlayout = new QVBoxLayout(page);
0156   m_edit = new QTextEdit(page);
0157   m_edit->setReadOnly(true);
0158   m_edit->setAcceptRichText(false);
0159   vlayout->addWidget(m_edit);
0160 }
0161 
0162 /**
0163  * Start dialog.
0164  *
0165  * @param taggedFile file to use for rename preview
0166  * @param dirName    if taggedFile is 0, the directory can be set here
0167  */
0168 void RenDirDialog::startDialog(TaggedFile* taggedFile, const QString& dirName)
0169 {
0170   m_taggedFile = taggedFile;
0171   if (m_taggedFile) {
0172     slotUpdateNewDirname();
0173   } else {
0174     m_currentDirLabel->setText(dirName);
0175     m_newDirLabel->clear();
0176   }
0177   restart();
0178 }
0179 
0180 /**
0181  * Set new directory name.
0182  *
0183  * @param dir new directory name
0184  */
0185 void RenDirDialog::setNewDirname(const QString& dir)
0186 {
0187   m_newDirLabel->setText(dir);
0188 }
0189 
0190 /**
0191  * Get new directory name.
0192  *
0193  * @return new directory name.
0194  */
0195 QString RenDirDialog::getNewDirname() const
0196 {
0197   return m_newDirLabel->text();
0198 }
0199 
0200 /**
0201  * Set configuration from dialog in directory renamer.
0202  */
0203 void RenDirDialog::setDirRenamerConfiguration() {
0204   m_dirRenamer->setTagVersion(Frame::tagVersionCast(
0205     m_tagversionComboBox->itemData(m_tagversionComboBox->currentIndex()).toInt()));
0206   m_dirRenamer->setAction(m_actionComboBox->currentIndex() == ActionCreate);
0207   m_format = m_formatComboBox->currentText();
0208   m_dirRenamer->setFormat(m_format);
0209 }
0210 
0211 /**
0212  * Set new directory name according to current settings.
0213  */
0214 void RenDirDialog::slotUpdateNewDirname()
0215 {
0216   if (m_taggedFile) {
0217     setDirRenamerConfiguration();
0218     QString currentDirname;
0219     QString newDirname(m_dirRenamer->generateNewDirname(m_taggedFile,
0220                                                         &currentDirname));
0221     m_currentDirLabel->setText(currentDirname);
0222     setNewDirname(newDirname);
0223   }
0224 }
0225 
0226 /**
0227  * Save the local settings to the configuration.
0228  */
0229 void RenDirDialog::saveConfig()
0230 {
0231   RenDirConfig& renDirCfg = RenDirConfig::instance();
0232   m_format = m_formatComboBox->currentText();
0233   setFormats();
0234   renDirCfg.setDirFormats(m_formats);
0235   renDirCfg.setDirFormat(m_format);
0236   renDirCfg.setRenDirSource(Frame::tagVersionCast(
0237     m_tagversionComboBox->itemData(m_tagversionComboBox->currentIndex()).toInt()));
0238   QByteArray geometry = saveGeometry();
0239   renDirCfg.setWindowGeometry(geometry);
0240   restoreGeometry(geometry); // Keep geometry when dialog is reopened
0241 }
0242 
0243 /**
0244  * Show help.
0245  */
0246 void RenDirDialog::showHelp()
0247 {
0248   ContextHelp::displayHelp(QLatin1String("rename-directory"));
0249 }
0250 
0251 /**
0252  * Request action scheduling and then accept dialog.
0253  */
0254 void RenDirDialog::requestActionSchedulingAndAccept()
0255 {
0256   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0257   setDirRenamerConfiguration();
0258   emit actionSchedulingRequested();
0259   QApplication::restoreOverrideCursor();
0260   accept();
0261 }
0262 
0263 /**
0264  * Clear action preview.
0265  */
0266 void RenDirDialog::clearPreview()
0267 {
0268   if (m_edit) {
0269     m_edit->clear();
0270     m_edit->setLineWrapMode(QTextEdit::NoWrap);
0271   }
0272 }
0273 
0274 /**
0275  * Display action preview.
0276  *
0277  * @param actionStrs description of action
0278  */
0279 void RenDirDialog::displayActionPreview(const QStringList& actionStrs)
0280 {
0281   QString str = actionStrs.at(0);
0282 #if QT_VERSION >= 0x050b00
0283   int width = fontMetrics().horizontalAdvance(str) + 8;
0284 #else
0285   int width = fontMetrics().width(str) + 8;
0286 #endif
0287 #if QT_VERSION >= 0x050a00
0288   if (m_edit->tabStopDistance() < width) {
0289     m_edit->setTabStopDistance(width);
0290   }
0291 #else
0292   if (m_edit->tabStopWidth() < width) {
0293     m_edit->setTabStopWidth(width);
0294   }
0295 #endif
0296   if (actionStrs.size() > 1) {
0297     str += QLatin1Char('\t');
0298     str += actionStrs.at(1);
0299   }
0300   if (actionStrs.size() > 2) {
0301     str += QLatin1String("\n\t");
0302     str += actionStrs.at(2);
0303   }
0304   m_edit->append(str);
0305 }
0306 
0307 /**
0308  * Wizard page changed.
0309  */
0310 void RenDirDialog::pageChanged()
0311 {
0312   if (currentId() == 1) {
0313     clearPreview();
0314     setDirRenamerConfiguration();
0315     emit actionSchedulingRequested();
0316   }
0317 }
0318 
0319 /**
0320  * Open dialog to edit formats.
0321  */
0322 void RenDirDialog::editFormats()
0323 {
0324   setFormats();
0325   if (StringListEditDialog dialog(m_formats, tr("Folder Name from Tag"), this);
0326       dialog.exec() == QDialog::Accepted) {
0327     m_formats = dialog.stringList();
0328     setFormats();
0329   }
0330 }
0331 
0332 /**
0333  * Set items of format combo box from configuration.
0334  */
0335 void RenDirDialog::setFormats()
0336 {
0337   int idx = m_formats.indexOf(m_format);
0338   if (idx == -1) {
0339     m_formats.append(m_format);
0340     idx = m_formats.size() - 1;
0341   }
0342   m_formatComboBox->blockSignals(true);
0343   if (!m_formats.isEmpty()) {
0344     m_formatComboBox->clear();
0345     m_formatComboBox->addItems(m_formats);
0346   }
0347   m_formatComboBox->setCurrentIndex(idx);
0348   m_formatComboBox->blockSignals(false);
0349 }
0350 
0351 /**
0352  * Called when the wizard is canceled.
0353  */
0354 void RenDirDialog::reject()
0355 {
0356   m_dirRenamer->abort();
0357   QWizard::reject();
0358 }