Commit e1d64675 authored by Urs Fleisch's avatar Urs Fleisch
Browse files

improved rename directory wizard

parent ba57a1c1
......@@ -240,8 +240,8 @@ QString Kid3App::s_dirName;
* Constructor.
*/
Kid3App::Kid3App() :
m_importDialog(0), m_exportDialog(0), m_numberTracksDialog(0),
m_filterDialog(0)
m_importDialog(0), m_exportDialog(0), m_renDirDialog(0),
m_numberTracksDialog(0), m_filterDialog(0)
{
#ifdef CONFIG_USE_KDE
#if KDE_VERSION >= 0x035c00
......@@ -303,6 +303,7 @@ Kid3App::Kid3App() :
Kid3App::~Kid3App()
{
delete m_importDialog;
delete m_renDirDialog;
delete m_numberTracksDialog;
delete m_filterDialog;
#ifndef CONFIG_USE_KDE
......@@ -2170,32 +2171,69 @@ void Kid3App::slotApplyId3Format()
updateGuiControls();
}
#if defined HAVE_ID3LIB && defined HAVE_TAGLIB
/**
* Perform renaming or creation of directory on files in directory.
* Read file with TagLib if it has an ID3v2.4 tag.
*
* @param dialog RenDirDialog instance
* @param errorMsg an error message is returned here
* @param item file list item, can be updated
* @param taggedFile tagged file
*
* @return true if ok.
* @return tagged file (can be new TagLibFile).
*/
bool Kid3App::performRenameDirectoryAction(RenDirDialog* dialog, QString& errorMsg)
static TaggedFile* readWithTagLibIfId3V24(FileListItem* item,
TaggedFile* taggedFile)
{
FileListItem* mp3file = m_view->firstFileInDir();
bool again = false;
while (mp3file &&
dialog->performAction(mp3file->getFile(), again, &errorMsg)) {
mp3file = m_view->nextFileInDir();
if (dynamic_cast<Mp3File*>(taggedFile) != 0 &&
!taggedFile->isChanged() &&
taggedFile->isTagInformationRead() && taggedFile->hasTagV2() &&
taggedFile->getTagFormatV2() == QString::null) {
TagLibFile* tagLibFile;
if ((tagLibFile = new TagLibFile(
taggedFile->getDirInfo(),
taggedFile->getFilename())) != 0) {
item->setFile(tagLibFile);
taggedFile = tagLibFile;
taggedFile->readTags(false);
}
}
openDirectory(dialog->getNewDirname());
if (again) {
mp3file = m_view->firstFileInDir();
while (mp3file &&
dialog->performAction(mp3file->getFile(), again, &errorMsg)) {
mp3file = m_view->nextFileInDir();
return taggedFile;
}
#endif
/**
* Schedule actions to rename a directory.
*/
void Kid3App::scheduleRenameActions()
{
if (m_renDirDialog) {
m_renDirDialog->clearActions();
TaggedFile* taggedFile;
FileListItem* item = m_view->firstFileOrDir();
while (item) {
if (item->getDirInfo()) {
#if QT_VERSION >= 0x040000
item->setExpanded(true);
#else
item->setOpen(true);
#endif
} else if ((taggedFile = item->getFile()) != 0) {
taggedFile->readTags(false);
#if defined HAVE_ID3LIB && defined HAVE_TAGLIB
taggedFile = readWithTagLibIfId3V24(item, taggedFile);
#endif
m_renDirDialog->scheduleAction(taggedFile);
}
item = m_view->nextFileOrDir();
#ifdef CONFIG_USE_KDE
kapp->processEvents();
#else
qApp->processEvents();
#endif
if (m_renDirDialog->getAbortFlag()) {
break;
}
}
openDirectory(dialog->getNewDirname());
}
return errorMsg.isEmpty();
}
/**
......@@ -2214,18 +2252,25 @@ bool Kid3App::renameDirectory(int tagMask, const QString& format,
{
bool ok = false;
if (!isModified() && m_view->firstFileInDir()) {
RenDirDialog* dialog =
new RenDirDialog(0, m_view->firstFileInDir()->getFile());
if (dialog) {
if (!m_renDirDialog) {
m_renDirDialog = new RenDirDialog(0);
connect(m_renDirDialog, SIGNAL(actionSchedulingRequested()),
this, SLOT(scheduleRenameActions()));
}
if (m_renDirDialog) {
m_renDirDialog->startDialog(m_view->firstFileInDir()->getFile());
m_renDirDialog->setTagSource(tagMask);
m_renDirDialog->setDirectoryFormat(format);
m_renDirDialog->setAction(create);
scheduleRenameActions();
openDirectory(getDirName());
QString errorMsg;
dialog->setTagSource(tagMask);
dialog->setDirectoryFormat(format);
dialog->setAction(create);
ok = performRenameDirectoryAction(dialog, errorMsg);
m_renDirDialog->performActions(&errorMsg);
openDirectory(m_renDirDialog->getNewDirname());
ok = errorMsg.isEmpty();
if (errStr) {
*errStr = errorMsg;
}
delete dialog;
}
}
return ok;
......@@ -2236,20 +2281,49 @@ bool Kid3App::renameDirectory(int tagMask, const QString& format,
*/
void Kid3App::slotRenameDirectory()
{
if (saveModified() && m_view->firstFileInDir()) {
RenDirDialog* dialog =
new RenDirDialog(0, m_view->firstFileInDir()->getFile());
if (dialog) {
if (dialog->exec() == QDialog::Accepted) {
if (saveModified()) {
if (!m_renDirDialog) {
m_renDirDialog = new RenDirDialog(0);
connect(m_renDirDialog, SIGNAL(actionSchedulingRequested()),
this, SLOT(scheduleRenameActions()));
}
if (m_renDirDialog) {
FileListItem* item = m_view->currentFile();
if (item && item->isSelected()) {
TaggedFile* taggedFile;
const DirInfo* dirInfo = item->getDirInfo();
if (dirInfo) {
#if QT_VERSION >= 0x040000
item->setExpanded(true);
#else
item->setOpen(true);
#endif
} else if ((taggedFile = item->getFile()) != 0) {
dirInfo = taggedFile->getDirInfo();
}
if (dirInfo) {
openDirectory(dirInfo->getDirname());
}
}
item = m_view->firstFileInDir();
if (item) {
m_renDirDialog->startDialog(item->getFile());
} else {
m_renDirDialog->startDialog(0, getDirName());
}
if (m_renDirDialog->exec() == QDialog::Accepted) {
openDirectory(getDirName());
QString errorMsg;
if (!performRenameDirectoryAction(dialog, errorMsg)) {
m_renDirDialog->performActions(&errorMsg);
openDirectory(m_renDirDialog->getNewDirname());
if (!errorMsg.isEmpty()) {
QMessageBox::warning(0, i18n("File Error"),
i18n("Error while renaming:\n") +
errorMsg,
QMessageBox::Ok, QCM_NoButton);
i18n("Error while renaming:\n") +
errorMsg,
QMessageBox::Ok, QCM_NoButton);
}
}
delete dialog;
}
}
}
......@@ -2310,35 +2384,6 @@ void Kid3App::slotNumberTracks()
}
}
#if defined HAVE_ID3LIB && defined HAVE_TAGLIB
/**
* Read file with TagLib if it has an ID3v2.4 tag.
*
* @param item file list item, can be updated
* @param taggedFile tagged file
*
* @return tagged file (can be new TagLibFile).
*/
static TaggedFile* readWithTagLibIfId3V24(FileListItem* item,
TaggedFile* taggedFile)
{
if (dynamic_cast<Mp3File*>(taggedFile) != 0 &&
!taggedFile->isChanged() &&
taggedFile->isTagInformationRead() && taggedFile->hasTagV2() &&
taggedFile->getTagFormatV2() == QString::null) {
TagLibFile* tagLibFile;
if ((tagLibFile = new TagLibFile(
taggedFile->getDirInfo(),
taggedFile->getFilename())) != 0) {
item->setFile(tagLibFile);
taggedFile = tagLibFile;
taggedFile->readTags(false);
}
}
return taggedFile;
}
#endif
/**
* Apply a file filter.
*
......
......@@ -68,6 +68,7 @@ class StandardTags;
class FrameList;
class ImportDialog;
class ExportDialog;
class RenDirDialog;
class NumberTracksDialog;
class RenDirDialog;
class FilterDialog;
......@@ -587,6 +588,11 @@ private slots:
*/
void applyFilter(FileFilter& fileFilter);
/**
* Schedule actions to rename a directory.
*/
void scheduleRenameActions();
private:
friend class ScriptInterface;
......@@ -678,16 +684,6 @@ private:
*/
bool importTags(int tagMask, const QString& path, int fmtIdx);
/**
* Perform renaming or creation of directory on files in directory.
*
* @param dialog RenDirDialog instance
* @param errorMsg an error message is returned here
*
* @return true if ok.
*/
bool performRenameDirectoryAction(RenDirDialog* dialog, QString& errorMsg);
/**
* Show or hide the ID3V1.1 controls according to the settings and
* set the menu entries appropriately.
......@@ -728,6 +724,8 @@ private:
ImportTrackDataVector m_trackDataList;
/** Export dialog */
ExportDialog* m_exportDialog;
/** Rename directory dialog */
RenDirDialog* m_renDirDialog;
/** Number tracks dialog */
NumberTracksDialog* m_numberTracksDialog;
/** Filter dialog */
......
......@@ -29,6 +29,9 @@
#include <qcombobox.h>
#include <qlabel.h>
#include <qdir.h>
#include <qapplication.h>
#include <qtextedit.h>
#include <qcursor.h>
#include "qtcompatmac.h"
#if QT_VERSION >= 0x040000
#include <QVBoxLayout>
......@@ -45,25 +48,113 @@
/**
* Constructor.
*
* @param parent parent widget
* @param taggedFile file to use for rename preview
* @param parent parent widget
*/
RenDirDialog::RenDirDialog(QWidget* parent, TaggedFile* taggedFile) :
QDialog(parent), m_taggedFile(taggedFile)
#if QT_VERSION >= 0x040000
#if QT_VERSION >= 0x040300
RenDirDialog::RenDirDialog(QWidget* parent) :
QWizard(parent), m_taggedFile(0), m_aborted(false)
{
setModal(true);
QCM_setWindowTitle(i18n("Rename Directory"));
QWizardPage* mainPage = new QWizardPage;
QVBoxLayout* mainLayout = new QVBoxLayout(mainPage);
setupMainPage(mainPage, mainLayout);
mainPage->setTitle(i18n("Format"));
addPage(mainPage);
QWizardPage* previewPage = new QWizardPage;
setupPreviewPage(previewPage);
previewPage->setTitle(i18n("Preview"));
addPage(previewPage);
setOptions(HaveHelpButton | HaveCustomButton1);
setButtonText(CustomButton1, i18n("&Save Settings"));
connect(this, SIGNAL(helpRequested()), this, SLOT(showHelp()));
connect(this, SIGNAL(customButtonClicked(int)), this, SLOT(saveConfig()));
connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(pageChanged()));
}
#else
RenDirDialog::RenDirDialog(QWidget* parent) :
QDialog(parent), m_edit(0), m_taggedFile(0), m_aborted(false)
{
setModal(true);
QCM_setWindowTitle(i18n("Rename Directory"));
QVBoxLayout* vlayout = new QVBoxLayout(this);
if (!vlayout) {
return ;
setupMainPage(this, vlayout);
QHBoxLayout* hlayout = new QHBoxLayout;
QSpacerItem* hspacer = new QSpacerItem(16, 0, QSizePolicy::Expanding,
QSizePolicy::Minimum);
QPushButton* helpButton = new QPushButton(i18n("&Help"), this);
QPushButton* saveButton = new QPushButton(i18n("&Save Settings"), this);
QPushButton* okButton = new QPushButton(i18n("&OK"), this);
QPushButton* cancelButton = new QPushButton(i18n("&Cancel"), this);
if (vlayout && hlayout && helpButton && saveButton && okButton && cancelButton) {
hlayout->addWidget(helpButton);
hlayout->addWidget(saveButton);
hlayout->addItem(hspacer);
hlayout->addWidget(okButton);
hlayout->addWidget(cancelButton);
okButton->setDefault(true);
connect(helpButton, SIGNAL(clicked()), this, SLOT(showHelp()));
connect(saveButton, SIGNAL(clicked()), this, SLOT(saveConfig()));
connect(okButton, SIGNAL(clicked()),
this, SLOT(requestActionSchedulingAndAccept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
vlayout->addLayout(hlayout);
}
}
#endif
#else
RenDirDialog::RenDirDialog(QWidget* parent) :
QWizard(parent), m_taggedFile(0), m_aborted(false)
{
setModal(true);
QCM_setWindowTitle(i18n("Rename Directory"));
QWidget* mainPage = new QWidget(this);
QVBoxLayout* mainLayout = new QVBoxLayout(mainPage);
setupMainPage(mainPage, mainLayout);
addPage(mainPage, i18n("Format"));
QWidget* previewPage = new QWidget(this);
setupPreviewPage(previewPage);
addPage(previewPage, i18n("Preview"));
setFinishEnabled(previewPage, true);
connect(this, SIGNAL(helpClicked()), this, SLOT(showHelp()));
connect(this, SIGNAL(selected(const QString&)), this, SLOT(pageChanged()));
}
#endif
/**
* Destructor.
*/
RenDirDialog::~RenDirDialog()
{}
/**
* Set up the main wizard page.
*
* @param page widget
* @param vlayout layout
*/
void RenDirDialog::setupMainPage(QWidget* page, QVBoxLayout* vlayout)
{
if (!page || !vlayout) {
return;
}
vlayout->setSpacing(6);
vlayout->setMargin(6);
QHBoxLayout* actionLayout = new QHBoxLayout;
m_actionComboBox = new QComboBox(this);
m_tagversionComboBox = new QComboBox(this);
m_actionComboBox = new QComboBox(page);
m_tagversionComboBox = new QComboBox(page);
if (m_actionComboBox && m_tagversionComboBox) {
m_actionComboBox->QCM_insertItem(ActionRename, i18n("Rename Directory"));
m_actionComboBox->QCM_insertItem(ActionCreate, i18n("Create Directory"));
......@@ -77,8 +168,8 @@ RenDirDialog::RenDirDialog(QWidget* parent, TaggedFile* taggedFile) :
vlayout->addLayout(actionLayout);
}
QHBoxLayout* formatLayout = new QHBoxLayout;
QLabel* formatLabel = new QLabel(i18n("&Format:"), this);
m_formatComboBox = new QComboBox(this);
QLabel* formatLabel = new QLabel(i18n("&Format:"), page);
m_formatComboBox = new QComboBox(page);
if (formatLayout && formatLabel && m_formatComboBox) {
QStringList strList;
for (const char** sl = MiscConfig::s_defaultDirFmtList; *sl != 0; ++sl) {
......@@ -109,10 +200,10 @@ RenDirDialog::RenDirDialog(QWidget* parent, TaggedFile* taggedFile) :
#else
QGridLayout* fromToLayout = new QGridLayout(vlayout, 2, 2);
#endif
QLabel* fromLabel = new QLabel(i18n("From:"), this);
m_currentDirLabel = new QLabel(this);
QLabel* toLabel = new QLabel(i18n("To:"), this);
m_newDirLabel = new QLabel(this);
QLabel* fromLabel = new QLabel(i18n("From:"), page);
m_currentDirLabel = new QLabel(page);
QLabel* toLabel = new QLabel(i18n("To:"), page);
m_newDirLabel = new QLabel(page);
if (fromToLayout && fromLabel && m_currentDirLabel &&
toLabel && m_newDirLabel) {
fromToLayout->addWidget(fromLabel, 0, 0);
......@@ -120,35 +211,49 @@ RenDirDialog::RenDirDialog(QWidget* parent, TaggedFile* taggedFile) :
fromToLayout->addWidget(toLabel, 1, 0);
fromToLayout->addWidget(m_newDirLabel, 1, 1);
}
}
QHBoxLayout* hlayout = new QHBoxLayout;
QSpacerItem* hspacer = new QSpacerItem(16, 0, QSizePolicy::Expanding,
QSizePolicy::Minimum);
QPushButton* helpButton = new QPushButton(i18n("&Help"), this);
QPushButton* saveButton = new QPushButton(i18n("&Save Settings"), this);
QPushButton* okButton = new QPushButton(i18n("&OK"), this);
QPushButton* cancelButton = new QPushButton(i18n("&Cancel"), this);
if (hlayout && helpButton && saveButton && okButton && cancelButton) {
hlayout->addWidget(helpButton);
hlayout->addWidget(saveButton);
hlayout->addItem(hspacer);
hlayout->addWidget(okButton);
hlayout->addWidget(cancelButton);
okButton->setDefault(true);
connect(helpButton, SIGNAL(clicked()), this, SLOT(showHelp()));
connect(saveButton, SIGNAL(clicked()), this, SLOT(saveConfig()));
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
vlayout->addLayout(hlayout);
/**
* Set up the preview wizard page.
*
* @param page widget
*/
void RenDirDialog::setupPreviewPage(QWidget* page)
{
QVBoxLayout* vlayout = new QVBoxLayout(page);
if (vlayout) {
m_edit = new QTextEdit(page);
if (m_edit) {
m_edit->setReadOnly(true);
m_edit->QCM_setTextFormat_PlainText();
vlayout->addWidget(m_edit);
}
}
slotUpdateNewDirname();
}
/**
* Destructor.
* Start dialog.
*
* @param taggedFile file to use for rename preview
* @param dirName if taggedFile is 0, the directory can be set here
*/
RenDirDialog::~RenDirDialog()
{}
void RenDirDialog::startDialog(TaggedFile* taggedFile, const QString& dirName)
{
m_taggedFile = taggedFile;
if (m_taggedFile) {
slotUpdateNewDirname();
} else {
m_currentDirLabel->setText(dirName);
m_newDirLabel->clear();
}
#if QT_VERSION >= 0x040000
#if QT_VERSION >= 0x040300
restart();
#endif
#else
showPage(page(0));
#endif
}
/**
* Get parent directory.
......@@ -297,6 +402,9 @@ QString RenDirDialog::generateNewDirname(TaggedFile* taggedFile, QString* olddir
}
}
QString newdir(taggedFile->getDirname());
#ifdef WIN32
newdir.replace('\\', '/');
#endif
if (newdir.endsWith(QChar('/'))) {
// remove trailing separator
newdir.truncate(newdir.length() - 1);
......@@ -316,9 +424,9 @@ QString RenDirDialog::generateNewDirname(TaggedFile* taggedFile, QString* olddir
}
/**
* Get new directory name.
* Set new directory name.
*
* @return new directory name.
* @param dir new directory name
*/
void RenDirDialog::setNewDirname(const QString& dir)
{
......@@ -349,93 +457,215 @@ void RenDirDialog::slotUpdateNewDirname()
}
/**
* Perform renaming or creation of directory according to current settings.
* Clear the rename actions.
* This method has to be called before scheduling new actions.
*/
void RenDirDialog::clearActions()
{
m_actions.clear();
m_aborted = false;
}
/**
* Add a rename action.
*
* @param type type of action
* @param src source file or directory name
* @param dest destination file or directory name
*/
void RenDirDialog::addAction(RenameAction::Type type, const QString& src, const QString& dest)
{
// do not add an action if the source or destination is already in an action
for (RenameActionList::const_iterator it = m_actions.begin();
it != m_actions.end();
++it) {
if ((!src.isEmpty() && (*it).m_src == src) ||
(!dest.isEmpty() && (*it).m_dest == dest)){
return;
}
}
m_actions.push_back(RenameAction(type, src, dest));
}
/**
* Add a rename action.
*
* @param type type of action
* @param dest destination file or directory name
*/
void RenDirDialog::addAction(RenameAction::Type type, const QString& dest)
{
addAction(type, QString(), dest);
}
/**
* Check if there is already an action scheduled for this source.
*
* @param taggedFile file to take directory from and to move
* @param again is set true if the new directory (getNewDirname())
* should be read and processed again
* @param errorMsg if not NULL and an error occurred, a message is appended here,
* otherwise it is not touched
* @return true if a rename action for the source exists.
*/
bool RenDirDialog::actionHasSource(const QString& src) const
{
if (src.isEmpty()) {
return false;
}
for (RenameActionList::const_iterator it = m_actions.begin();
it != m_actions.end();
++it) {
if ((*it).m_src == src) {
return true;
}
}
return false;
}
/**
* Check if there is already an action scheduled for this destination.
*
* @return true if other files can be processed,
* false if operation is finished.
* @return true if a rename or create action for the destination exists.
*/
bool RenDirDialog::performAction(TaggedFile* taggedFile, bool& again, QString* errorMsg)