File indexing completed on 2024-12-08 11:10:44

0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 // SPDX-FileCopyrightText: 2001 Dominik Seichter <domseichter@web.de>
0003 
0004 #ifndef BATCHRENAMER_H
0005 #define BATCHRENAMER_H
0006 
0007 #include <QList>
0008 #include <QObject>
0009 
0010 #include "krenamefile.h"
0011 
0012 class QFile;
0013 class QProgressDialog;
0014 class QString;
0015 class QTextStream;
0016 
0017 typedef struct __tag_tCounterValues {
0018     int value;  // current value of this counter
0019     int start;  // start value of this counter (for findResetCounter)
0020     int step;   // stepping value of this counter;
0021 } tCounterValues;
0022 
0023 /** A structure describing a string or regular
0024  *  expression that is to be found in the final/resulting
0025  *  filename and to be replaced with another string.
0026  */
0027 typedef struct __tag_TReplaceItem {
0028     QString find;         ///< Text to replace
0029     QString replace;      ///< Replace with
0030     bool reg;             ///< is it a reg expression ?
0031     bool doProcessTokens; ///< Process tokens in result
0032 } TReplaceItem;
0033 
0034 /** An enum to set the renaming mode of KRename
0035  */
0036 enum ERenameMode {
0037     eRenameMode_Rename,  ///< All files are renamed in place
0038     eRenameMode_Move,    ///< All files are moved to a new directory and renamed
0039     eRenameMode_Copy,    ///< Only copies of the files are renamed
0040     eRenameMode_Link     ///< Symbolic links are created and renamed
0041 };
0042 
0043 class QObject;
0044 class ProgressDialog;
0045 
0046 /** This is the core class for renaming.
0047  *
0048  *  It transforms the filenames according to
0049  *  the users settings using custom functions
0050  *  and external plugins.
0051  *  Also the actual renaming, copying or moving
0052  *  of the files is done by this class
0053  *
0054  *  @author Dominik Seichter
0055  */
0056 class BatchRenamer : public QObject
0057 {
0058     Q_OBJECT
0059 
0060 public:
0061     BatchRenamer();
0062     ~BatchRenamer() override;
0063 
0064     /** Sets the list of files
0065      *  which contains all filenames which should be transformed.
0066      *
0067      *  The renamed filenames are stored in this list, too,.
0068      *
0069      *  @param list a list of KRenameFile objects
0070      */
0071     inline void setFiles(KRenameFile::List *list);
0072 
0073     /** Get access to the list of files used for renaming.
0074      *  @returns the list of files or NULL if none was set.
0075      */
0076     inline const KRenameFile::List *files() const;
0077 
0078     /**
0079      *  @returns the current renaming mode
0080      */
0081     inline ERenameMode renameMode() const;
0082 
0083     /**
0084      * @returns the current start index for counters
0085      */
0086     inline int numberStartIndex() const;
0087 
0088     /**
0089      * @returns the stepping for counters
0090      */
0091     inline int numberStepping() const;
0092 
0093     /**
0094      * @returns if counters are reset on new directories
0095      */
0096     inline int numberReset() const;
0097 
0098     /**
0099      * @returns the list of numbers that are skipped during renaming
0100      */
0101     inline QList<int> numberSkipList() const;
0102 
0103     /** Does the actuall renaming,
0104      *  transforming all source filenames in the file list
0105      *  to the new destination filenames.
0106      *
0107      *  No actuall renaming is done, only the new filenames
0108      *  are calculated.
0109      */
0110     void processFilenames();
0111 
0112     /** Process all files
0113      *
0114      *  processFilenames has to be called before
0115      *
0116      *  All files will be renamed according to the users settings.
0117      *
0118      *  Output will be reported through a progress dialog
0119      *
0120      *  @param p use this dialog to report progress to the user
0121      */
0122     void processFiles(ProgressDialog *p);
0123 
0124     /** undo all files
0125      *
0126      *  processFiles has to be called before
0127      *
0128      *  A previous renaming operation will be undone.
0129      *
0130      *  Output will be reported through a progress dialog
0131      *
0132      *  @param p use this dialog to report progress to the user
0133      */
0134     void undoFiles(ProgressDialog *p);
0135 
0136     /** Build the destination url from a KRenameFile
0137      *
0138      *  @param file a KRenameFile
0139      *  @returns a valid QUrl
0140      */
0141     const QUrl buildDestinationUrl(const KRenameFile &file) const;
0142 
0143     inline void setUndoScript(const QString &t)
0144     {
0145         m_undoScript = t;
0146     }
0147     inline void setUndo(bool b)
0148     {
0149         undo = b;
0150     }
0151 
0152     inline void setReplaceList(const QList<TReplaceItem> &r)
0153     {
0154         m_replace = r;
0155     }
0156     inline const QList<TReplaceItem> &replaceList() const
0157     {
0158         return m_replace;
0159     }
0160 
0161     inline void setMode(int m)
0162     {
0163         m_mode = m;
0164     }
0165     inline int mode() const
0166     {
0167         return m_mode;
0168     }
0169 
0170     QString findToken(const QString &oldname, QString token, int i);
0171     QString findPartStrings(QString oldname, QString token);
0172     static QString findDirName(QString token, QString path);
0173 
0174     /**
0175      * Replace the token [dirsep] with a slash "/".
0176      * This token is useful to create directories from within regular expressions.
0177      */
0178     static QString findDirSep(const QString &token, const QString &path);
0179 
0180     static QString &doEscape(QString &text);
0181     static QString &unEscape(QString &text);
0182     static void escape(QString &text, const QString &token, const QString &sequence);
0183 
0184     /** Capitalize a string.
0185      *
0186      *  Used to implement the * token.
0187      *
0188      *  @param a text string
0189      *  @return a capitalized version of this string (every first letter is a capital letter now)
0190      */
0191     QString capitalize(const QString &text) const;
0192 
0193     /** Handle the [length] tokens
0194      *
0195      *  @param token a token found in square brackets
0196      *  @param name the filename of the current file
0197      *
0198      *  @return an empty QString if no length token was found or the new string
0199      */
0200     QString findLength(const QString &token, const QString &name);
0201 
0202     /** Handle the [trimmed] token
0203      *
0204      *  @param token a token found in square brackets
0205      *  @param name the filename of the current file
0206     *  @param index index of the current file
0207            *
0208            *  @return an empty QString if no length token was found or the new string
0209            */
0210     QString findTrimmed(const QString &token, const QString &name, int index);
0211 
0212     QString processString(QString text, const QString &originalName, int i, bool doFindReplace = true);
0213     QString processBrackets(QString text, int *length, const QString &oldname, int index);
0214     QString processNumber(int length, const QString &appendix);
0215     QString processToken(const QString &token, const QString &oldname, int i);
0216 
0217 public Q_SLOTS:
0218 
0219     /** Sets the current mode of renaming.
0220      *  KRename can rename files, move them while
0221      *  renaming to another directory, rename copies
0222      *  or create renamed sym-links.
0223      *
0224      *  This mode specifies what should be done with the files.
0225      *
0226      *  @param mode the renaming mode.
0227      */
0228     inline void setRenameMode(ERenameMode mode);
0229 
0230     /** Sets the template for the filename that is used
0231      *  to transform the filename to its final representation.
0232      *
0233      *  @param t the new template
0234      */
0235     inline void setFilenameTemplate(const QString &t);
0236 
0237     /** Sets the template for the filename that is used
0238      *  to transform the filename to its final representation.
0239      *
0240      *  @param t the new template
0241      */
0242     inline void setExtensionTemplate(const QString &t);
0243 
0244     /** Set the start index for the basic counters
0245      *  which do not specify an own start index in their
0246      *  appendiy (e.g. ###{7}, means 7 is the start index
0247      *
0248      *  @param i start index
0249      */
0250     inline void setNumberStartIndex(int i)
0251     {
0252         m_index = i;
0253     }
0254 
0255     /** Set the stepping for the basic counters
0256      *  which do not specify an own stepping in their
0257      *  appendiy (e.g. ###{1,2}, means 2 is the stepping
0258      *
0259      *  @param s stepping
0260      */
0261     inline void setNumberStepping(int s)
0262     {
0263         m_step = s;
0264     }
0265 
0266     /** Sets whether all counters should be reset for new
0267      *  directories
0268      *
0269      *  @param r if true counters will be reset
0270      */
0271     inline void setNumberReset(bool r)
0272     {
0273         m_reset = r;
0274     }
0275 
0276     /** Sets the list of numbers that are skipped by counters
0277      *
0278      *  @param s a list of numbers that is skipped
0279      */
0280     inline void setNumberSkipList(const QList<int> &s)
0281     {
0282         m_skip = s;
0283     }
0284 
0285     /** Sets if existing files maybe overwritten during renaming
0286      *
0287      *  @param overwrite if true existing files will be overwritten
0288      */
0289     inline void setOverwriteExistingFiles(bool overwrite)
0290     {
0291         m_overwrite = overwrite;
0292     }
0293 
0294     /** Sets the destination url (a directory) for copy, move and link operations
0295      *
0296      *  @param url destination directory
0297      */
0298     inline void setDestinationDir(const QUrl &url)
0299     {
0300         m_destination = url;
0301     }
0302 
0303 private:
0304     /** Do find and replace on the final resulting filename.
0305      *
0306      *  \param text the new final filename with all other changes applied.
0307      *
0308      *  \returns the new filename with all find and replace being done.
0309      *
0310      *  \see m_replace
0311      */
0312     QString findReplace(const QString &text, const QString &origFilename, int index);
0313 
0314     /**
0315      * Replace one string (which might be a regular expression) in the final filename
0316      * with another string and return a new filename.
0317      *
0318      *  \param text the new final filename with all other changes applied.
0319      *  \param find the string or regular expression to find
0320      *  \param replace replace a matched string with this value
0321      *  \param reg if true treat find as regular expression
0322      *  \param doProcessTokens process tokens in replaced results
0323      *  \param originalName original filename for replacing tokens
0324      *  \param index current index
0325      *
0326      *  \returns the new filename with find and replace being done.
0327      */
0328     QString doReplace(const QString &text, const QString &find, const QString &replace,
0329                       bool reg, bool doProcessTokens, const QString &origFilename, int index);
0330 
0331 private:
0332     /** Execute all plugins of a certain type
0333      *
0334      *  @param index the current index
0335      *  @param filenameOrPath the current filename or path
0336      *  @param type the type of the plugins to run
0337      *  @param errorCount the number of errors will be written to this value
0338      *  @param p dialog for error reporting (maybe NULL)
0339      *
0340      *  @returns either a new filename or an error message (depends on plugin type)
0341      */
0342     QString executePlugin(int index, const QString &filenameOrPath, int type, int &errorCount, ProgressDialog *p);
0343 
0344     void work(ProgressDialog *p);
0345     void writeUndoScript(QTextStream *t);
0346 
0347     /**
0348      * Parse a new filename and create missing subdirectories.
0349      *
0350      * This will look for '/' and create all not existing directories
0351      *
0352      * @param destUrl to check for not existing directories
0353      * @param dialog ProgressDialog for error reporting
0354      */
0355     void createMissingSubDirs(const QUrl &destUrl, ProgressDialog *dialog);
0356 
0357     /** resets all counters to there start value if the directory name at @p i
0358      *  in m_files changes.
0359      *  The caller has to check m_reset before calling this function.
0360      */
0361     void findCounterReset(int i);
0362 
0363     QString text;           // template
0364     QString extext;         // Extension template
0365     QString m_undoScript;     // Filename of undoscript
0366     bool undo;              // create an undo script
0367     bool m_reset;             // reset counter on new directories
0368     int m_mode;             // renaming mode
0369     QList<int> m_skip; // Numbers to skip
0370 
0371     // a is used in find number and
0372     // required for skipping.
0373     int m_counter_index;
0374     int m_index;              // index for numbers
0375     int m_step;               // step for numbers
0376 
0377     QList<tCounterValues> m_counters;
0378 
0379 private:
0380     KRenameFile::List *m_files;       ///< The list of files to rename and the resulting renamed filenames
0381     ERenameMode        m_renameMode;  ///< The rename mode specifies if files are renamed, copied or moved (or linked)
0382     bool               m_overwrite;   ///< Overwrite existing files
0383     QUrl               m_destination; ///< Destination directory for copy, move and link
0384 
0385     QList<TReplaceItem> m_replace;    ///< List of strings for find and replace
0386 
0387 protected:
0388     QFile *f;
0389     QTime t;
0390     QProgressDialog *progress;
0391 };
0392 
0393 void BatchRenamer::setFiles(KRenameFile::List *list)
0394 {
0395     m_files = list;
0396 }
0397 
0398 const KRenameFile::List *BatchRenamer::files() const
0399 {
0400     return m_files;
0401 }
0402 
0403 void BatchRenamer::setRenameMode(ERenameMode mode)
0404 {
0405     m_renameMode = mode;
0406 }
0407 
0408 ERenameMode BatchRenamer::renameMode() const
0409 {
0410     return m_renameMode;
0411 }
0412 
0413 void BatchRenamer::setFilenameTemplate(const QString &t)
0414 {
0415     text = t;
0416 }
0417 
0418 void BatchRenamer::setExtensionTemplate(const QString &t)
0419 {
0420     extext = t;
0421 }
0422 
0423 int BatchRenamer::numberStartIndex() const
0424 {
0425     return m_index;
0426 }
0427 
0428 int BatchRenamer::numberStepping() const
0429 {
0430     return m_step;
0431 }
0432 
0433 int BatchRenamer::numberReset() const
0434 {
0435     return m_reset;
0436 }
0437 
0438 QList<int> BatchRenamer::numberSkipList() const
0439 {
0440     return m_skip;
0441 }
0442 
0443 #endif