File indexing completed on 2021-12-21 13:28:02

0001 /**
0002  * Copyright (C) 2004 Michael Pyne <mpyne@kde.org>
0003  *
0004  * This program is free software; you can redistribute it and/or modify it under
0005  * the terms of the GNU General Public License as published by the Free Software
0006  * Foundation; either version 2 of the License, or (at your option) any later
0007  * version.
0008  *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
0012  *
0013  * You should have received a copy of the GNU General Public License along with
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.
0015  */
0016 
0017 #include "tagtransactionmanager.h"
0018 
0019 #include <KMessageBox>
0020 #include <KLocalizedString>
0021 
0022 #include <QAction>
0023 #include <QApplication>
0024 #include <QFileInfo>
0025 #include <QDir>
0026 #include <QGlobalStatic>
0027 
0028 #include "playlistitem.h"
0029 #include "collectionlist.h"
0030 #include "juktag.h"
0031 #include "actioncollection.h"
0032 #include "juk_debug.h"
0033 
0034 using ActionCollection::action;
0035 
0036 Q_GLOBAL_STATIC(TagTransactionManager, g_tagManager)
0037 
0038 TagTransactionManager *TagTransactionManager::instance()
0039 {
0040     return g_tagManager;
0041 }
0042 
0043 TagTransactionAtom::TagTransactionAtom(PlaylistItem *item, Tag *tag)
0044     : m_item(item)
0045     , m_tag(tag)
0046 {
0047 }
0048 
0049 void TagTransactionManager::changeTagOnItem(PlaylistItem *item, Tag *newTag)
0050 {
0051     if(!item) {
0052         qCWarning(JUK_LOG) << "Trying to change tag on null PlaylistItem.\n";
0053         return;
0054     }
0055 
0056     // Save the CollectionListItem, as it is the most likely to survive long
0057     // enough for the commit().  I should probably intercept the item deleted
0058     // signals from CollectionList to ensure that the commit list and the
0059     // playlists stay in sync.
0060 
0061     m_list.emplace_back(item->collectionItem(), newTag);
0062 }
0063 
0064 Tag *TagTransactionManager::duplicateTag(const Tag *tag, const QString &fileName)
0065 {
0066     Q_ASSERT(tag);
0067 
0068     QString name = fileName.isEmpty() ? tag->fileName() : fileName;
0069     Tag *newTag = new Tag(*tag);
0070 
0071     newTag->setFileName(name);
0072     return newTag;
0073 }
0074 
0075 bool TagTransactionManager::commit()
0076 {
0077     m_undoList.clear();
0078     bool result = processChangeList();
0079 
0080     m_list.clear();
0081     return result;
0082 }
0083 
0084 void TagTransactionManager::forget()
0085 {
0086     m_list.clear();
0087 }
0088 
0089 bool TagTransactionManager::undo()
0090 {
0091     qCDebug(JUK_LOG) << "Undoing " << m_undoList.size() << " changes.\n";
0092 
0093     forget();  // Scrap our old changes (although the list should be empty
0094                // anyways.
0095 
0096     bool result = processChangeList(true);
0097 
0098     m_undoList.clear();
0099     action("edit_undo")->setEnabled(false);
0100 
0101     return result;
0102 }
0103 
0104 bool TagTransactionManager::renameFile(const QFileInfo &from, const QFileInfo &to) const
0105 {
0106    if(!QFileInfo(to.path()).isWritable() || !from.exists())
0107        return false;
0108 
0109    if(!to.exists() ||
0110        KMessageBox::warningContinueCancel(
0111            static_cast<QWidget *>(parent()),
0112            i18n("This file already exists.\nDo you want to replace it?"),
0113            i18n("File Exists"),KGuiItem(i18n("Replace"))) == KMessageBox::Continue)
0114    {
0115        qCDebug(JUK_LOG) << "Renaming " << from.absoluteFilePath() << " to " << to.absoluteFilePath();
0116        QDir currentDir;
0117        return currentDir.rename(from.absoluteFilePath(), to.absoluteFilePath());
0118    }
0119 
0120    return false;
0121 }
0122 
0123 bool TagTransactionManager::processChangeList(bool undo)
0124 {
0125     TagAlterationList::const_iterator it, end;
0126     QStringList errorItems;
0127 
0128     it = undo ? m_undoList.cbegin() : m_list.cbegin();
0129     end = undo ? m_undoList.cend() : m_list.cend();
0130 
0131     emit signalAboutToModifyTags();
0132 
0133     for(; it != end; ++it) {
0134         PlaylistItem *item = (*it).item();
0135         const Tag *tag = (*it).tag();
0136 
0137         QFileInfo newFile(tag->fileName());
0138 
0139         if(item->file().fileInfo().fileName() != newFile.fileName()) {
0140             if(!renameFile(item->file().fileInfo(), newFile)) {
0141                 errorItems.append(item->text(1) + QString(" - ") + item->text(0));
0142                 continue;
0143             }
0144         }
0145 
0146         if(tag->save()) {
0147             if(!undo)
0148                 m_undoList.emplace_back(item, duplicateTag(item->file().tag()));
0149 
0150             item->setFile(tag->fileName());
0151             item->refreshFromDisk();
0152             //FIXME repaint
0153             //item->repaint();
0154             item->playlist()->playlistItemsChanged();
0155             item->playlist()->update();
0156         }
0157         else {
0158             Tag *errorTag = item->file().tag();
0159             QString str = errorTag->artist() + " - " + errorTag->title();
0160 
0161             if(errorTag->artist().isEmpty())
0162                 str = errorTag->title();
0163 
0164             errorItems.append(str);
0165         }
0166 
0167         qApp->processEvents();
0168     }
0169 
0170     undo ? m_undoList.clear() : m_list.clear();
0171     if(!undo && !m_undoList.empty())
0172         action("edit_undo")->setEnabled(true);
0173     else
0174         action("edit_undo")->setEnabled(false);
0175 
0176     if(!errorItems.isEmpty())
0177         KMessageBox::errorList(static_cast<QWidget *>(parent()),
0178                 i18n("The following files were unable to be changed."),
0179                 errorItems,
0180                 i18n("Error"));
0181 
0182     emit signalDoneModifyingTags();
0183     return errorItems.isEmpty();
0184 }
0185 
0186 // vim: set et sw=4 tw=0 sta: