File indexing completed on 2024-04-28 13:44:22

0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 // SPDX-FileCopyrightText: 2007 Dominik Seichter <domseichter@web.de>
0003 
0004 #include "krenamefile.h"
0005 
0006 #include <kio/previewjob.h>
0007 #include <KJobWidgets>
0008 #include <kio_version.h>
0009 
0010 /** A singleton class that loads icons for urls in a synchronous way
0011  */
0012 class KRenamePreviewProvider
0013 {
0014 
0015 public:
0016     /** Get the KRenamePreviewProvider instance. This is a singleton
0017      *  as only one KRenamePreviewProvider may exist for one application.
0018      */
0019     static KRenamePreviewProvider *Instance()
0020     {
0021         if (!s_instance) {
0022             s_instance = new KRenamePreviewProvider();
0023         }
0024 
0025         return s_instance;
0026     }
0027 
0028     QPixmap loadIcon(const QUrl &url)
0029     {
0030         return KIO::pixmapForUrl(url);
0031     }
0032 
0033 private:
0034     /** Create a KRenamePreviewProvider
0035      */
0036     KRenamePreviewProvider()
0037     {
0038     }
0039 
0040     ~KRenamePreviewProvider()
0041     {
0042     }
0043 
0044 private:
0045     static KRenamePreviewProvider *s_instance;
0046 };
0047 
0048 KRenamePreviewProvider *KRenamePreviewProvider::s_instance = nullptr;
0049 
0050 const int KRenameFile::DEFAULT_ICON_SIZE = 64;
0051 int KRenameFile::m_iconSize = 0; // read from config file
0052 const char *KRenameFile::EXTRA_DATA_KEY = "KRenameFile::EXTRA_DATA_KEY";
0053 
0054 KRenameFile::KRenameFile(const QUrl &src, ESplitMode eSplitMode, unsigned int dot)
0055     : m_bValid(false), m_error(0), m_manualMode(eManualChangeMode_None)
0056 {
0057 #if KIO_VERSION >= QT_VERSION_CHECK(5, 69, 0)
0058     KIO::StatJob *statJob = KIO::statDetails(src, KIO::StatJob::DestinationSide, KIO::StatDefaultDetails);
0059 #else
0060     KIO::StatJob *statJob = KIO::stat(src, KIO::StatJob::DestinationSide, 2);
0061 #endif
0062     statJob->exec();
0063     if (statJob->error()) {
0064         return;
0065     }
0066 
0067     KFileItem file(statJob->statResult(), src);
0068 
0069     m_bValid     = file.isReadable();
0070     m_bDirectory = file.isDir();
0071 
0072     m_fileItem = file;
0073     initFileDescription(m_src, src, eSplitMode, dot);
0074 }
0075 
0076 KRenameFile::KRenameFile(const QUrl &src, bool directory, ESplitMode eSplitMode, unsigned int dot)
0077     : m_bDirectory(directory), m_bValid(true), m_error(0), m_manualMode(eManualChangeMode_None)
0078 {
0079     initFileDescription(m_src, src, eSplitMode, dot);
0080 }
0081 
0082 KRenameFile::KRenameFile(const KFileItem &item, ESplitMode eSplitMode, unsigned int dot)
0083     : m_bDirectory(item.isDir()), m_bValid(item.isReadable()), m_error(0), m_manualMode(eManualChangeMode_None)
0084 {
0085     m_fileItem = item;
0086 
0087     initFileDescription(m_src, item.url(), eSplitMode, dot);
0088 }
0089 
0090 KRenameFile::KRenameFile(const KRenameFile &rhs)
0091 {
0092     this->operator=(rhs);
0093 }
0094 
0095 const KRenameFile &KRenameFile::operator=(const KRenameFile &rhs)
0096 {
0097     m_bDirectory = rhs.m_bDirectory;
0098     m_src        = rhs.m_src;
0099     m_dst        = rhs.m_dst;
0100 
0101     m_bValid     = rhs.m_bValid;
0102     m_icon       = rhs.m_icon;
0103     m_error      = rhs.m_error;
0104     m_manual     = rhs.m_manual;
0105     m_manualMode = rhs.m_manualMode;
0106 
0107     return *this;
0108 }
0109 
0110 bool KRenameFile::operator==(const KFileItem &item) const
0111 {
0112     return this->fileItem() == item;
0113 }
0114 
0115 void KRenameFile::setIconSize(int size)
0116 {
0117     m_iconSize = size;
0118 }
0119 
0120 int KRenameFile::iconSize()
0121 {
0122     return m_iconSize;
0123 }
0124 
0125 int KRenameFile::getDefaultIconSize()
0126 {
0127     return DEFAULT_ICON_SIZE;
0128 }
0129 
0130 void KRenameFile::setCurrentSplitMode(ESplitMode eSplitMode, unsigned int dot)
0131 {
0132     QUrl    url      = m_src.url;
0133     QString filename = m_src.filename;
0134     if (!m_src.extension.isEmpty()) {
0135         filename = filename + '.' + m_src.extension;
0136     }
0137 
0138     url.setPath(m_src.directory + '/' + filename);
0139 
0140     this->initFileDescription(m_src, url, eSplitMode, dot);
0141 }
0142 
0143 void KRenameFile::initFileDescription(TFileDescription &rDescription, const QUrl &url,
0144                                       ESplitMode eSplitMode, unsigned int dot) const
0145 {
0146     int splitPos = -1;
0147     QString path = url.path();
0148     QString file;
0149 
0150     if (!m_bValid) {
0151         return;
0152     }
0153 
0154     rDescription.url       = url;
0155     rDescription.directory = path;
0156 
0157     if (!m_bDirectory) {
0158         // split directory/filename
0159         splitPos = path.lastIndexOf('/');
0160         if (splitPos == -1) {
0161             // only a filename?? can this happen?
0162             file = path;
0163             path.clear();
0164         } else {
0165             file = path.right(path.length() - splitPos - 1);
0166             path.truncate(splitPos);
0167         }
0168 
0169         // split filename.extension
0170         splitPos = -1;
0171         if (eSplitMode == eSplitMode_FirstDot) {
0172             splitPos = file.indexOf('.');
0173         } else if (eSplitMode == eSplitMode_LastDot) {
0174             splitPos = file.lastIndexOf('.');
0175         } else if (eSplitMode == eSplitMode_NoExtension) {
0176             splitPos = file.length();
0177         } else {
0178             if (dot) {
0179                 int i = 0;
0180                 splitPos = 0;
0181                 do {
0182                     splitPos = file.indexOf('.', splitPos + 1);
0183                     ++i;
0184                 } while (i < static_cast<int>(dot) && splitPos != -1);
0185             } else
0186                 // if dot == 0, do not take an extension
0187             {
0188                 splitPos = file.length();
0189             }
0190         }
0191 
0192         if (splitPos == -1) {
0193             splitPos = file.length();
0194         }
0195 
0196         rDescription.filename  = file.left(splitPos);
0197         rDescription.extension = "";
0198         if (splitPos != file.length()) {
0199             rDescription.extension = file.right(file.length() - splitPos - 1);
0200         }
0201         rDescription.directory = path;
0202     } else {
0203         if (rDescription.directory.endsWith('/')) {
0204             rDescription.directory = rDescription.directory.left(rDescription.directory.length() - 1);
0205         }
0206 
0207         int lastSlash = rDescription.directory.lastIndexOf('/');
0208         rDescription.filename  = rDescription.directory.right(rDescription.directory.length() - lastSlash - 1);
0209         rDescription.directory.truncate(lastSlash);
0210         rDescription.extension = "";
0211     }
0212 
0213     /*
0214     qDebug("URL : %s", url.toDisplayString().toLatin1().data() );
0215     qDebug("Path: %s", rDescription.directory.toLatin1().data());
0216     qDebug("File: %s", rDescription.filename.toLatin1().data());
0217     qDebug("Ext : %s", rDescription.extension.toLatin1().data());
0218     qDebug("Split %i", splitPos );
0219     qDebug("Dot   %i", dot );
0220     qDebug("=====");
0221     */
0222 }
0223 
0224 void KRenameFile::loadPreviewIcon()
0225 {
0226     m_icon = KRenamePreviewProvider::Instance()->loadIcon(m_src.url);
0227 }
0228 
0229 int KRenameFile::dots() const
0230 {
0231     int dots = 0;
0232 
0233     dots += m_src.filename.count('.');
0234     dots += m_src.extension.count('.');
0235 
0236     if (!m_src.extension.isEmpty()) {
0237         ++dots;
0238     }
0239 
0240     return dots;
0241 }
0242 
0243 const QUrl KRenameFile::srcUrl() const
0244 {
0245     if (m_overrideDir.isNull()) {
0246         return m_src.url;
0247     } else {
0248         QUrl changed = m_src.url;
0249         QString filename = m_src.filename;
0250         if (!m_src.extension.isEmpty()) {
0251             filename += '.';
0252             filename += m_src.extension;
0253         }
0254 
0255         changed.setPath(m_overrideDir + '/' +  filename);
0256         return changed;
0257     }
0258 }
0259 
0260 const KFileItem &KRenameFile::fileItem() const
0261 {
0262     if (m_fileItem.isNull()) {
0263         // No file item has been constructed
0264         // create one first.
0265 #if KIO_VERSION >= QT_VERSION_CHECK(5, 69, 0)
0266         KIO::StatJob *statJob = KIO::statDetails(m_src.url, KIO::StatJob::DestinationSide, KIO::StatDefaultDetails);
0267 #else
0268         KIO::StatJob *statJob = KIO::stat(m_src.url, KIO::StatJob::DestinationSide, 2);
0269 #endif
0270         statJob->exec();
0271         if (!statJob->error()) {
0272             KFileItem file(statJob->statResult(), m_src.url);
0273             const_cast<KRenameFile *>(this)->m_fileItem = file;
0274         }
0275     }
0276 
0277     /*
0278     // Update extra as often as possible
0279     // As the address is changed through sorting and moving files
0280     // It is only valid if no moving of data has happened!
0281     const_cast<KRenameFile*>(this)->m_fileItem.setExtraData( KRenameFile::EXTRA_DATA_KEY,
0282                                                              const_cast<KRenameFile*>(this) );
0283     */
0284     return m_fileItem;
0285 }