1 /**
2  * \file rendirdialog.cpp
3  * Rename directory dialog.
4  *
5  * \b Project: Kid3
6  * \author Urs Fleisch
7  * \date 21 Mar 2004
8  *
9  * Copyright (C) 2004-2018  Urs Fleisch
10  *
11  * This file is part of Kid3.
12  *
13  * Kid3 is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * Kid3 is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #include "rendirdialog.h"
28 #include <QLayout>
29 #include <QPushButton>
30 #include <QComboBox>
31 #include <QLabel>
32 #include <QDir>
33 #include <QApplication>
34 #include <QTextEdit>
35 #include <QCursor>
36 #include <QVBoxLayout>
37 #include <QFormLayout>
38 #include "taggedfile.h"
39 #include "frame.h"
40 #include "trackdata.h"
41 #include "contexthelp.h"
42 #include "rendirconfig.h"
43 #include "dirrenamer.h"
44 #include "stringlisteditdialog.h"
45 
46 /**
47  * Constructor.
48  *
49  * @param parent parent widget
50  * @param dirRenamer directory renamer
51  */
RenDirDialog(QWidget * parent,DirRenamer * dirRenamer)52 RenDirDialog::RenDirDialog(QWidget* parent, DirRenamer* dirRenamer)
53   : QWizard(parent), m_taggedFile(nullptr), m_dirRenamer(dirRenamer)
54 {
55   setObjectName(QLatin1String("RenDirDialog"));
56   setModal(true);
57   setWindowTitle(tr("Rename Folder"));
58   setSizeGripEnabled(true);
59 
60   auto mainPage = new QWizardPage;
61 
62   auto mainLayout = new QVBoxLayout(mainPage);
63   setupMainPage(mainPage, mainLayout);
64   mainPage->setTitle(tr("Format"));
65   addPage(mainPage);
66 
67   auto previewPage = new QWizardPage;
68   setupPreviewPage(previewPage);
69   previewPage->setTitle(tr("Preview"));
70   addPage(previewPage);
71 
72   setOptions(HaveHelpButton | HaveCustomButton1);
73   setButtonText(CustomButton1, tr("&Save Settings"));
74   connect(this, &QWizard::helpRequested, this, &RenDirDialog::showHelp);
75   connect(this, &QWizard::customButtonClicked, this, &RenDirDialog::saveConfig);
76   connect(this, &QWizard::currentIdChanged, this, &RenDirDialog::pageChanged);
77 }
78 
79 /**
80  * Set up the main wizard page.
81  *
82  * @param page    widget
83  * @param vlayout layout
84  */
setupMainPage(QWidget * page,QVBoxLayout * vlayout)85 void RenDirDialog::setupMainPage(QWidget* page, QVBoxLayout* vlayout)
86 {
87   if (!page || !vlayout) {
88     return;
89   }
90 
91   auto actionLayout = new QFormLayout;
92   actionLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
93   m_actionComboBox = new QComboBox(page);
94   m_tagversionComboBox = new QComboBox(page);
95   m_actionComboBox->insertItem(ActionRename, tr("Rename Folder"));
96   m_actionComboBox->insertItem(ActionCreate, tr("Create Folder"));
97   actionLayout->addRow(tr("&Action:"), m_actionComboBox);
98   connect(m_actionComboBox, static_cast<void (QComboBox::*)(int)>(
99             &QComboBox::activated), this, &RenDirDialog::slotUpdateNewDirname);
100   const QList<QPair<Frame::TagVersion, QString> > tagVersions =
101       Frame::availableTagVersions();
102   for (auto it = tagVersions.constBegin(); it != tagVersions.constEnd(); ++it) {
103     m_tagversionComboBox->addItem(it->second, it->first);
104   }
105   actionLayout->addRow(tr("&Source:"), m_tagversionComboBox);
106   connect(m_tagversionComboBox, static_cast<void (QComboBox::*)(int)>(
107             &QComboBox::activated), this, &RenDirDialog::slotUpdateNewDirname);
108 
109   auto formatLayout = new QHBoxLayout;
110   m_formatComboBox = new QComboBox(page);
111   m_formatComboBox->setEditable(true);
112   const RenDirConfig& renDirCfg = RenDirConfig::instance();
113   m_formats = renDirCfg.dirFormats();
114   m_format = renDirCfg.dirFormat();
115   setFormats();
116   formatLayout->addWidget(m_formatComboBox, 1);
117   auto editFormatsButton = new QPushButton(tr("&Edit..."));
118   connect(editFormatsButton, &QPushButton::clicked,
119           this, &RenDirDialog::editFormats);
120   formatLayout->addWidget(editFormatsButton);
121   auto formatLabel = new QLabel(tr("&Format:"));
122   formatLabel->setBuddy(m_formatComboBox);
123   actionLayout->addRow(formatLabel, formatLayout);
124   m_tagversionComboBox->setCurrentIndex(
125         m_tagversionComboBox->findData(renDirCfg.renDirSource()));
126   connect(m_formatComboBox, static_cast<void (QComboBox::*)(int)>(
127             &QComboBox::activated), this, &RenDirDialog::slotUpdateNewDirname);
128   connect(m_formatComboBox, &QComboBox::editTextChanged,
129           this, &RenDirDialog::slotUpdateNewDirname);
130 
131   m_currentDirLabel = new QLabel(page);
132   m_newDirLabel = new QLabel(page);
133   actionLayout->addRow(tr("From:"), m_currentDirLabel);
134   actionLayout->addRow(tr("To:"), m_newDirLabel);
135 
136   vlayout->addLayout(actionLayout);
137 
138   QByteArray geometry = renDirCfg.windowGeometry();
139   if (!geometry.isEmpty()) {
140     restoreGeometry(geometry);
141   }
142 }
143 
144 /**
145  * Set up the preview wizard page.
146  *
147  * @param page widget
148  */
setupPreviewPage(QWidget * page)149 void RenDirDialog::setupPreviewPage(QWidget* page)
150 {
151   auto vlayout = new QVBoxLayout(page);
152   m_edit = new QTextEdit(page);
153   m_edit->setReadOnly(true);
154   m_edit->setAcceptRichText(false);
155   vlayout->addWidget(m_edit);
156 }
157 
158 /**
159  * Start dialog.
160  *
161  * @param taggedFile file to use for rename preview
162  * @param dirName    if taggedFile is 0, the directory can be set here
163  */
startDialog(TaggedFile * taggedFile,const QString & dirName)164 void RenDirDialog::startDialog(TaggedFile* taggedFile, const QString& dirName)
165 {
166   m_taggedFile = taggedFile;
167   if (m_taggedFile) {
168     slotUpdateNewDirname();
169   } else {
170     m_currentDirLabel->setText(dirName);
171     m_newDirLabel->clear();
172   }
173   restart();
174 }
175 
176 /**
177  * Set new directory name.
178  *
179  * @param dir new directory name
180  */
setNewDirname(const QString & dir)181 void RenDirDialog::setNewDirname(const QString& dir)
182 {
183   m_newDirLabel->setText(dir);
184 }
185 
186 /**
187  * Get new directory name.
188  *
189  * @return new directory name.
190  */
getNewDirname() const191 QString RenDirDialog::getNewDirname() const
192 {
193   return m_newDirLabel->text();
194 }
195 
196 /**
197  * Set configuration from dialog in directory renamer.
198  */
setDirRenamerConfiguration()199 void RenDirDialog::setDirRenamerConfiguration() {
200   m_dirRenamer->setTagVersion(Frame::tagVersionCast(
201     m_tagversionComboBox->itemData(m_tagversionComboBox->currentIndex()).toInt()));
202   m_dirRenamer->setAction(m_actionComboBox->currentIndex() == ActionCreate);
203   m_format = m_formatComboBox->currentText();
204   m_dirRenamer->setFormat(m_format);
205 }
206 
207 /**
208  * Set new directory name according to current settings.
209  */
slotUpdateNewDirname()210 void RenDirDialog::slotUpdateNewDirname()
211 {
212   if (m_taggedFile) {
213     setDirRenamerConfiguration();
214     QString currentDirname;
215     QString newDirname(m_dirRenamer->generateNewDirname(m_taggedFile,
216                                                         &currentDirname));
217     m_currentDirLabel->setText(currentDirname);
218     setNewDirname(newDirname);
219   }
220 }
221 
222 /**
223  * Save the local settings to the configuration.
224  */
saveConfig()225 void RenDirDialog::saveConfig()
226 {
227   RenDirConfig& renDirCfg = RenDirConfig::instance();
228   m_format = m_formatComboBox->currentText();
229   setFormats();
230   renDirCfg.setDirFormats(m_formats);
231   renDirCfg.setDirFormat(m_format);
232   renDirCfg.setRenDirSource(Frame::tagVersionCast(
233     m_tagversionComboBox->itemData(m_tagversionComboBox->currentIndex()).toInt()));
234   QByteArray geometry = saveGeometry();
235   renDirCfg.setWindowGeometry(geometry);
236   restoreGeometry(geometry); // Keep geometry when dialog is reopened
237 }
238 
239 /**
240  * Show help.
241  */
showHelp()242 void RenDirDialog::showHelp()
243 {
244   ContextHelp::displayHelp(QLatin1String("rename-directory"));
245 }
246 
247 /**
248  * Request action scheduling and then accept dialog.
249  */
requestActionSchedulingAndAccept()250 void RenDirDialog::requestActionSchedulingAndAccept()
251 {
252   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
253   setDirRenamerConfiguration();
254   emit actionSchedulingRequested();
255   QApplication::restoreOverrideCursor();
256   accept();
257 }
258 
259 /**
260  * Clear action preview.
261  */
clearPreview()262 void RenDirDialog::clearPreview()
263 {
264   if (m_edit) {
265     m_edit->clear();
266     m_edit->setLineWrapMode(QTextEdit::NoWrap);
267   }
268 }
269 
270 /**
271  * Display action preview.
272  *
273  * @param actionStrs description of action
274  */
displayActionPreview(const QStringList & actionStrs)275 void RenDirDialog::displayActionPreview(const QStringList& actionStrs)
276 {
277   QString str = actionStrs.at(0);
278 #if QT_VERSION >= 0x050b00
279   int width = fontMetrics().horizontalAdvance(str) + 8;
280 #else
281   int width = fontMetrics().width(str) + 8;
282 #endif
283 #if QT_VERSION >= 0x050a00
284   if (m_edit->tabStopDistance() < width) {
285     m_edit->setTabStopDistance(width);
286   }
287 #else
288   if (m_edit->tabStopWidth() < width) {
289     m_edit->setTabStopWidth(width);
290   }
291 #endif
292   if (actionStrs.size() > 1) {
293     str += QLatin1Char('\t');
294     str += actionStrs.at(1);
295   }
296   if (actionStrs.size() > 2) {
297     str += QLatin1String("\n\t");
298     str += actionStrs.at(2);
299   }
300   m_edit->append(str);
301 }
302 
303 /**
304  * Wizard page changed.
305  */
pageChanged()306 void RenDirDialog::pageChanged()
307 {
308   if (currentId() == 1) {
309     clearPreview();
310     setDirRenamerConfiguration();
311     emit actionSchedulingRequested();
312   }
313 }
314 
315 /**
316  * Open dialog to edit formats.
317  */
editFormats()318 void RenDirDialog::editFormats()
319 {
320   setFormats();
321   StringListEditDialog dialog(m_formats, tr("Folder Name from Tag"), this);
322   if (dialog.exec() == QDialog::Accepted) {
323     m_formats = dialog.stringList();
324     setFormats();
325   }
326 }
327 
328 /**
329  * Set items of format combo box from configuration.
330  */
setFormats()331 void RenDirDialog::setFormats()
332 {
333   int idx = m_formats.indexOf(m_format);
334   if (idx == -1) {
335     m_formats.append(m_format);
336     idx = m_formats.size() - 1;
337   }
338   m_formatComboBox->blockSignals(true);
339   if (!m_formats.isEmpty()) {
340     m_formatComboBox->clear();
341     m_formatComboBox->addItems(m_formats);
342   }
343   m_formatComboBox->setCurrentIndex(idx);
344   m_formatComboBox->blockSignals(false);
345 }
346 
347 /**
348  * Called when the wizard is canceled.
349  */
reject()350 void RenDirDialog::reject()
351 {
352   m_dirRenamer->abort();
353   QWizard::reject();
354 }
355