File indexing completed on 2023-05-30 11:30:53

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 <QDir>
0025 #include <QFileInfo>
0026 
0027 #include "playlistitem.h"
0028 #include "collectionlist.h"
0029 #include "juktag.h"
0030 #include "actioncollection.h"
0031 #include "juk_debug.h"
0032 
0033 using ActionCollection::action;
0034 
0035 Q_GLOBAL_STATIC(TagTransactionManager, g_tagManager)
0036 
0037 TagTransactionManager *TagTransactionManager::instance()
0038 {
0039     return g_tagManager;
0040 }
0041 
0042 TagTransactionAtom::TagTransactionAtom(PlaylistItem *item, Tag *tag)
0043     : m_item(item)
0044     , m_tag(tag)
0045 {
0046 }
0047 
0048 void TagTransactionManager::changeTagOnItem(PlaylistItem *item, Tag *newTag)
0049 {
0050     if(!item) {
0051         qCWarning(JUK_LOG) << "Trying to change tag on null PlaylistItem.\n";
0052         return;
0053     }
0054 
0055     // Save the CollectionListItem, as it is the most likely to survive long
0056     // enough for the commit().  I should probably intercept the item deleted
0057     // signals from CollectionList to ensure that the commit list and the
0058     // playlists stay in sync.
0059 
0060     m_list.emplace_back(item->collectionItem(), newTag);
0061 }
0062 
0063 Tag *TagTransactionManager::duplicateTag(const Tag *tag, const QString &fileName)
0064 {
0065     Q_ASSERT(tag);
0066 
0067     QString name = fileName.isEmpty() ? tag->fileName() : fileName;
0068     Tag *newTag = new Tag(*tag);
0069 
0070     newTag->setFileName(name);
0071     return newTag;
0072 }
0073 
0074 bool TagTransactionManager::commit()
0075 {
0076     m_undoList.clear();
0077     bool result = processChangeList();
0078 
0079     m_list.clear();
0080     return result;
0081 }
0082 
0083 void TagTransactionManager::forget()
0084 {
0085     m_list.clear();
0086 }
0087 
0088 bool TagTransactionManager::undo()
0089 {
0090     qCDebug(JUK_LOG) << "Undoing " << m_undoList.size() << " changes.\n";
0091 
0092     forget();  // Scrap our old changes (although the list should be empty
0093                // anyways.
0094 
0095     bool result = processChangeList(true);
0096 
0097     m_undoList.clear();
0098     action("edit_undo")->setEnabled(false);
0099 
0100     return result;
0101 }
0102 
0103 bool TagTransactionManager::renameFile(const QFileInfo &from, const QFileInfo &to) const
0104 {
0105    if(!QFileInfo(to.path()).isWritable() || !from.exists())
0106        return false;
0107 
0108    if(!to.exists() ||
0109        KMessageBox::warningContinueCancel(
0110            static_cast<QWidget *>(parent()),
0111            i18n("This file already exists.\nDo you want to replace it?"),
0112            i18n("File Exists"),KGuiItem(i18n("Replace"))) == KMessageBox::Continue)
0113    {
0114        qCDebug(JUK_LOG) << "Renaming " << from.absoluteFilePath() << " to " << to.absoluteFilePath();
0115        QDir currentDir;
0116        return currentDir.rename(from.absoluteFilePath(), to.absoluteFilePath());
0117    }
0118 
0119    return false;
0120 }
0121 
0122 bool TagTransactionManager::processChangeList(bool undo)
0123 {
0124     TagAlterationList::const_iterator it, end;
0125     QStringList errorItems;
0126 
0127     it = undo ? m_undoList.cbegin() : m_list.cbegin();
0128     end = undo ? m_undoList.cend() : m_list.cend();
0129 
0130     emit signalAboutToModifyTags();
0131 
0132     for(; it != end; ++it) {
0133         PlaylistItem *item = (*it).item();
0134         const Tag *tag = (*it).tag();
0135 
0136         QFileInfo newFile(tag->fileName());
0137 
0138         if(item->file().fileInfo().fileName() != newFile.fileName()) {
0139             if(!renameFile(item->file().fileInfo(), newFile)) {
0140                 errorItems.append(item->text(1) + QString(" - ") + item->text(0));
0141                 continue;
0142             }
0143         }
0144 
0145         if(tag->save()) {
0146             if(!undo)
0147                 m_undoList.emplace_back(item, duplicateTag(item->file().tag()));
0148 
0149             item->setFile(tag->fileName());
0150             item->refreshFromDisk();
0151             //FIXME repaint
0152             //item->repaint();
0153             item->playlist()->playlistItemsChanged();
0154             item->playlist()->update();
0155         }
0156         else {
0157             Tag *errorTag = item->file().tag();
0158             QString str = errorTag->artist() + " - " + errorTag->title();
0159 
0160             if(errorTag->artist().isEmpty())
0161                 str = errorTag->title();
0162 
0163             errorItems.append(str);
0164         }
0165 
0166         qApp->processEvents();
0167     }
0168 
0169     undo ? m_undoList.clear() : m_list.clear();
0170     if(!undo && !m_undoList.empty())
0171         action("edit_undo")->setEnabled(true);
0172     else
0173         action("edit_undo")->setEnabled(false);
0174 
0175     if(!errorItems.isEmpty())
0176         KMessageBox::errorList(static_cast<QWidget *>(parent()),
0177                 i18n("The following files were unable to be changed."),
0178                 errorItems,
0179                 i18n("Error"));
0180 
0181     emit signalDoneModifyingTags();
0182     return errorItems.isEmpty();
0183 }
0184 
0185 // vim: set et sw=4 tw=0 sta: