File indexing completed on 2024-05-12 05:46:51

0001 /* This file is part of the KDE libraries
0002    Copyright (C) 2017 by Chinmoy Ranjan Pradhan <chinmoyrp65@gmail.com>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Lesser General Public
0006    License as published by the Free Software Foundation; either
0007    version 2.1 of the License, or (at your option) version 3, or any
0008    later version accepted by the membership of KDE e.V. (or its
0009    successor approved by the membership of KDE e.V.), which shall
0010    act as a proxy defined in Section 6 of version 3 of the license.
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Lesser General Public License for more details.
0015 
0016    You should have received a copy of the GNU Lesser General Public
0017    License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0018 */
0019 
0020 #include "batchrenamejob.h"
0021 
0022 #include "job_p.h"
0023 #include "copyjob.h"
0024 
0025 #include <QTimer>
0026 #include <QSet>
0027 #include <QMimeDatabase>
0028 
0029 using namespace KIO;
0030 
0031 class KIO::BatchRenameJobPrivate : public KIO::JobPrivate
0032 {
0033 public:
0034     BatchRenameJobPrivate(const QList<QUrl> &src, const QString &newName,
0035                           int index, QChar placeHolder, JobFlags flags)
0036         : JobPrivate(),
0037           m_srcList(src),
0038           m_newName(newName),
0039           m_index(index),
0040           m_placeHolder(placeHolder),
0041           m_listIterator(m_srcList.constBegin()),
0042           m_allExtensionsDifferent(true),
0043           m_useIndex(true),
0044           m_appendIndex(false),
0045           m_flags(flags)
0046     {
0047         // There occur four cases when renaming multiple files,
0048         // 1. All files have different extension and $newName contains a valid placeholder.
0049         // 2. At least two files have same extension and $newName contains a valid placeholder.
0050         // In these two cases the placeholder character will be replaced by an integer($index).
0051         // 3. All files have different extension and new name contains an invalid placeholder
0052         //    (this means either $newName doesn't contain the placeholder or the placeholders
0053         //     are not in a connected sequence).
0054         // In this case nothing is substituted and all files have the same $newName.
0055         // 4. At least two files have same extension and $newName contains an invalid placeholder.
0056         // In this case $index is appended to $newName.
0057 
0058 
0059         // Check for extensions.
0060         QSet<QString> extensions;
0061         QMimeDatabase db;
0062         for (const QUrl &url : qAsConst(m_srcList)) {
0063             const QString extension = db.suffixForFileName(url.toDisplayString().toLower());
0064             if (extensions.contains(extension)) {
0065                 m_allExtensionsDifferent = false;
0066                 break;
0067             }
0068 
0069             extensions.insert(extension);
0070         }
0071 
0072         // Check for exactly one placeholder character or exactly one sequence of placeholders.
0073         int pos = newName.indexOf(placeHolder);
0074         if (pos != -1) {
0075             while (pos < newName.size() && newName.at(pos) == placeHolder) {
0076                 pos++;
0077             }
0078         }
0079         const bool validPlaceholder = (newName.indexOf(placeHolder, pos) == -1);
0080 
0081         if (!validPlaceholder) {
0082             if (!m_allExtensionsDifferent) {
0083                m_appendIndex = true;
0084             } else {
0085                m_useIndex = false;
0086             }
0087         }
0088     }
0089 
0090     QList<QUrl> m_srcList;
0091     QString m_newName;
0092     int m_index;
0093     QChar m_placeHolder;
0094     QList<QUrl>::const_iterator m_listIterator;
0095     bool m_allExtensionsDifferent;
0096     bool m_useIndex;
0097     bool m_appendIndex;
0098     QUrl m_newUrl; // for fileRenamed signal
0099     const JobFlags m_flags;
0100 
0101     Q_DECLARE_PUBLIC(BatchRenameJob)
0102 
0103     void slotStart();
0104 
0105     QString indexedName(const QString& name, int index, QChar placeHolder) const;
0106 
0107     static inline BatchRenameJob *newJob(const QList<QUrl> &src, const QString &newName,
0108                                          int index, QChar placeHolder, JobFlags flags)
0109     {
0110         BatchRenameJob *job = new BatchRenameJob(*new BatchRenameJobPrivate(src, newName, index, placeHolder, flags));
0111         job->setUiDelegate(KIO::createDefaultJobUiDelegate());
0112         if (!(flags & HideProgressInfo)) {
0113             KIO::getJobTracker()->registerJob(job);
0114         }
0115         if (!(flags & NoPrivilegeExecution)) {
0116             job->d_func()->m_privilegeExecutionEnabled = true;
0117             job->d_func()->m_operationType = Rename;
0118         }
0119         return job;
0120     }
0121 
0122 };
0123 
0124 BatchRenameJob::BatchRenameJob(BatchRenameJobPrivate &dd)
0125     : Job(dd)
0126 {
0127     QTimer::singleShot(0, this, SLOT(slotStart()));
0128 }
0129 
0130 BatchRenameJob::~BatchRenameJob()
0131 {
0132 }
0133 
0134 QString BatchRenameJobPrivate::indexedName(const QString& name, int index, QChar placeHolder) const
0135 {
0136     if (!m_useIndex) {
0137         return name;
0138     }
0139 
0140     QString newName = name;
0141     QString indexString = QString::number(index);
0142 
0143     if (m_appendIndex) {
0144         newName.append(indexString);
0145         return newName;
0146     }
0147 
0148     // Insert leading zeros if necessary
0149     const int minIndexLength = name.count(placeHolder);
0150     indexString.prepend(QString(minIndexLength - indexString.length(), QLatin1Char('0')));
0151 
0152     // Replace the index placeholders by the indexString
0153     const int placeHolderStart = newName.indexOf(placeHolder);
0154     newName.replace(placeHolderStart, minIndexLength, indexString);
0155 
0156     return newName;
0157 }
0158 
0159 void BatchRenameJobPrivate::slotStart()
0160 {
0161     Q_Q(BatchRenameJob);
0162 
0163     if (m_listIterator == m_srcList.constBegin()) { //  emit total
0164         q->setTotalAmount(KJob::Files, m_srcList.count());
0165     }
0166 
0167     if (m_listIterator != m_srcList.constEnd()) {
0168         QString newName = indexedName(m_newName, m_index, m_placeHolder);
0169         const QUrl oldUrl = *m_listIterator;
0170         QMimeDatabase db;
0171         const QString extension = db.suffixForFileName(oldUrl.path().toLower());
0172         if (!extension.isEmpty()) {
0173             newName += QLatin1Char('.') + extension;
0174         }
0175 
0176         m_newUrl = oldUrl.adjusted(QUrl::RemoveFilename);
0177         m_newUrl.setPath(m_newUrl.path() + KIO::encodeFileName(newName));
0178 
0179         KIO::Job * job = KIO::moveAs(oldUrl, m_newUrl, KIO::HideProgressInfo);
0180         job->setParentJob(q);
0181         q->addSubjob(job);
0182         q->setProcessedAmount(KJob::Files, q->processedAmount(KJob::Files) + 1);
0183     } else {
0184         q->emitResult();
0185     }
0186 }
0187 
0188 void BatchRenameJob::slotResult(KJob *job)
0189 {
0190     Q_D(BatchRenameJob);
0191     if (job->error()) {
0192         KIO::Job::slotResult(job);
0193         return;
0194     }
0195 
0196     removeSubjob(job);
0197 
0198     emit fileRenamed(*d->m_listIterator, d->m_newUrl);
0199     ++d->m_listIterator;
0200     ++d->m_index;
0201     emitPercent(d->m_listIterator - d->m_srcList.constBegin(), d->m_srcList.count());
0202     d->slotStart();
0203 }
0204 
0205 BatchRenameJob * KIO::batchRename(const QList<QUrl> &src, const QString &newName,
0206                                   int index, QChar placeHolder, KIO::JobFlags flags)
0207 {
0208     return BatchRenameJobPrivate::newJob(src, newName, index, placeHolder, flags);
0209 }
0210 
0211 
0212 #include "moc_batchrenamejob.cpp"