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"