diff --git a/src/batchrenamer.cpp b/src/batchrenamer.cpp index 421f17d..7c8c288 100644 --- a/src/batchrenamer.cpp +++ b/src/batchrenamer.cpp @@ -1,1179 +1,1181 @@ /*************************************************************************** batchrenamer.cpp - description ------------------- begin : Sat Aug 18 2001 copyright : (C) 2001 by Dominik Seichter email : domseichter@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "batchrenamer.h" +#include + #ifdef Q_OS_WIN #include #endif // OS includes #include #ifndef Q_OS_WIN #include #endif #include "../config-krename.h" // chmod: #include #include // QT includes #include // KDE includes #include #include #include // Own includes #include "progressdialog.h" #include "pluginloader.h" #include "plugin.h" using namespace KIO; static bool isToken(const QChar &token) { const QChar tokens[] = { QChar('&'), QChar('$'), QChar('%'), QChar('#'), QChar('['), QChar(']'), QChar('\\'), QChar('/'), QChar('{'), QChar('}'), QChar('*') }; const int count = 11; for (int i = 0; i < count; i++) if (token == tokens[i]) { return true; } return false; } static int getNextToken(const QString &text, QString &token, int pos = 0) { bool escaped = false; token.clear(); if (pos < 0) { return -1; } while (pos < text.length()) { if (!escaped && text[pos] == QChar('\\')) { escaped = true; } else if (!escaped && isToken(text[pos])) { token = text[pos]; return ++pos; } else { escaped = false; } ++pos; } return -1; } BatchRenamer::BatchRenamer() : m_index(0), m_step(1), m_files(nullptr), m_renameMode(eRenameMode_Rename) { m_counter_index = 0; m_reset = false; m_overwrite = false; } BatchRenamer::~BatchRenamer() { } void BatchRenamer::processFilenames() { m_counters.clear(); for (unsigned int i = 0; i < static_cast(m_files->count()); i++) { m_counter_index = 0; if (m_renameMode == eRenameMode_Rename) { // final Path = source Path (*m_files)[i].setDstDirectory((*m_files)[i].srcDirectory()); QUrl url = (*m_files)[i].srcUrl(); url = url.adjusted(QUrl::RemoveFilename); (*m_files)[i].setDstUrl(url); } else { (*m_files)[i].setDstUrl(m_destination); (*m_files)[i].setDstDirectory(m_destination.path()); } if (i > 0 && m_reset) { findCounterReset(i); } //qDebug("SRCFILENAME : %s", (*m_files)[i].srcFilename().toUtf8().data() ); //qDebug("DSTFILENAME SHOULD: %s", processString( text, (*m_files)[i].srcFilename(), i ).toUtf8().data() ); (*m_files)[i].setDstFilename(processString(text, (*m_files)[i].srcFilename(), i)); //qDebug("DSTFILENAME IS : %s", (*m_files)[i].dstFilename().toUtf8().data()); (*m_files)[i].setDstExtension(processString(extext, (*m_files)[i].srcExtension(), i)); // Let's run the plugins that change the final filename, // i.e the encodingsplugin int errors = 0; QString name = executePlugin(i, (*m_files)[i].dstFilename(), ePluginType_Filename, errors, nullptr); if (!name.isNull()) { (*m_files)[i].setDstFilename(name); } /* * take care of renamed directories and * correct the paths of their contents */ if ((m_renameMode == eRenameMode_Rename || m_renameMode == eRenameMode_Move) && (*m_files)[i].isDirectory()) { const QString topDir = (*m_files)[i].realSrcDirectory() + '/' + (*m_files)[i].srcFilename(); const QString replace = (*m_files)[i].dstDirectory() + '/' + (*m_files)[i].dstFilename(); for (int z = i + 1; z < m_files->count(); z++) { const QString &dir = (*m_files)[z].realSrcDirectory(); if (dir.startsWith(topDir)) { QString newDir = replace + dir.right(dir.length() - topDir.length()); if (newDir != dir) { (*m_files)[z].setOverrideSrcDirectory(newDir); } } } } #if 0 if (m_files[i].dir && (m_mode == RENAME || m_mode == MOVE)) { for (unsigned int c = i; c < m_files.count(); c++) { if (m_files[c].src.directory.left(m_files[i].src.name.length() + 1) == (m_files[i].src.name + "/")) { m_files[c].src.directory.replace(0, m_files[i].src.name.length(), m_files[i].dst.name); m_files[c].src.url.setPath(BatchRenamer::buildFilename(&m_files[c].src, true)); } } } #endif // 0 } } void BatchRenamer::processFiles(ProgressDialog *p) { int errors = 0; QUrl dest = (*m_files)[0].dstUrl(); // TODO: error handling if dest is empty // Give the user some information... p->setProgressTotalSteps(m_files->count()); p->setProgress(0); p->setDestination(dest); switch (m_renameMode) { default: case eRenameMode_Rename: p->print(i18n("Input files will be renamed.")); break; case eRenameMode_Copy: p->print(i18n("Files will be copied to: %1", dest.toDisplayString(QUrl::PreferLocalFile))); break; case eRenameMode_Move: p->print(i18n("Files will be moved to: %1", dest.toDisplayString(QUrl::PreferLocalFile))); break; case eRenameMode_Link: p->print(i18n("Symbolic links will be created in: %1", dest.toDisplayString(QUrl::PreferLocalFile))); break; } for (unsigned int i = 0; i < static_cast(m_files->count()); i++) { QUrl dstUrl = this->buildDestinationUrl((*m_files)[i]); //p->print( QString( "%1 -> %2" ).arg( (*m_files)[i].srcUrl().prettyUrl() ).arg( dstUrl.toDisplayString() ) ); p->setProgress(i + 1); if (p->wasCancelled()) { break; } // Assemble filenames - createMissingSubDirs((*m_files)[i], p); + createMissingSubDirs(dstUrl, p); KIO::JobFlags flags = (m_overwrite ? KIO::Overwrite : KIO::DefaultFlags) | KIO::HideProgressInfo; KIO::Job *job = nullptr; const QUrl &srcUrl = (*m_files)[i].srcUrl(); if (srcUrl == dstUrl) { p->warning(i18n("Cannot rename: source and target filename are equal: %1", srcUrl.toDisplayString(QUrl::PreferLocalFile))); //(*m_files)[i].setError( 1 ); //errors++; continue; } switch (m_renameMode) { default: case eRenameMode_Rename: case eRenameMode_Move: job = KIO::file_move(srcUrl, dstUrl, -1, flags); break; case eRenameMode_Copy: job = KIO::file_copy(srcUrl, dstUrl, -1, flags); break; case eRenameMode_Link: { if (!srcUrl.isLocalFile()) { // We can only do symlinks to local urls p->error(i18n("Cannot create symlink to non-local URL: %1", srcUrl.toDisplayString())); (*m_files)[i].setError(1); errors++; } else { job = KIO::symlink(srcUrl.path(), dstUrl, flags); } break; } } if (job) { KJobWidgets::setWindow(job, p); if (!job->exec()) { p->error(i18n("Error renaming %2 (to %1)", dstUrl.toDisplayString(QUrl::PreferLocalFile), srcUrl.toDisplayString(QUrl::PreferLocalFile))); (*m_files)[i].setError(job->error()); errors++; } } /* * The renamed file should be on its correct location now, * so that we can call the last plugins (e.g. for changing permissions) * * Remember, the token argument is the filename for this type of plugins! * * If the return value is not empty an error has occurred! * The plugin should return an error message in this case! */ int errorCount = 0; this->executePlugin(i, dstUrl.path(), ePluginType_File, errorCount, p); errors += errorCount; } if (errors > 0) { p->warning(i18np("%1 error occurred.", "%1 errors occurred.", errors)); } p->print(i18n("KRename finished the renaming process."), "krename"); p->print(i18n("Press close to quit.")); bool enableUndo = (m_renameMode != eRenameMode_Copy); p->renamingDone(true, enableUndo, this, errors); #if 0 delete object; t.start(); m_counters.clear(); for (unsigned int i = 0; i < m_files->count(); i++) { m_counter_index = 0; if (m_mode == RENAME) { // final Path = source Path m_files[i].dst.directory = m_files[i].src.directory; m_files[i].dst.url = m_files[i].src.url; m_files[i].dst.url.setFileName(QString::null); } else { m_files[i].dst.directory = m_destination.path(); m_files[i].dst.url = m_destination; } if (i == 0) { p->setDestination(m_files[i].dst.url); } else { if (m_reset) { findCounterReset(i); } } m_files[i].dst.name = processString(text, m_files[i].src.name, i); if (!extext.isEmpty()) { m_files[i].dst.extension = processString(extext, m_files[i].src.extension, i); } // Assemble filenames parseSubdirs(&m_files[i]); // TODO: DOM // ESCAPE HERE m_files[i].src.name = BatchRenamer::buildFilename(&m_files[i].src, true); // Let's run the plugins that change the final filename, // i.e the encodingsplugin m_files[i].dst.name = parsePlugins(i, m_files[i].dst.name, TYPE_FINAL_FILENAME); m_files[i].dst.name = BatchRenamer::buildFilename(&m_files[i].dst, true); /* * take care of renamed directories and * correct the paths of their contents */ if (m_files[i].dir && (m_mode == RENAME || m_mode == MOVE)) { for (unsigned int c = i; c < m_files.count(); c++) { if (m_files[c].src.directory.left(m_files[i].src.name.length() + 1) == (m_files[i].src.name + "/")) { m_files[c].src.directory.replace(0, m_files[i].src.name.length(), m_files[i].dst.name); m_files[c].src.url.setPath(BatchRenamer::buildFilename(&m_files[c].src, true)); } } } } p->print(QString(i18n("Filenames Processed after %1 seconds.", t.elapsed() / 1000))); work(p); #endif // 0 } void BatchRenamer::undoFiles(ProgressDialog *p) { int errors = 0; QUrl dest = (*m_files)[0].dstUrl(); // Give the user some information... p->setProgressTotalSteps(m_files->count()); p->setProgress(0); p->setDestination(dest); p->print(i18n("Undoing all renamed files.")); for (unsigned int i = 0; i < static_cast(m_files->count()); i++) { QUrl dstUrl = this->buildDestinationUrl((*m_files)[i]); //p->print( QString( "%1 -> %2" ).arg( (*m_files)[i].srcUrl().prettyUrl() ).arg( dstUrl.toDisplayString() ) ); p->setProgress(i + 1); if (p->wasCancelled()) { break; } KIO::JobFlags flags = (m_overwrite ? KIO::Overwrite : KIO::DefaultFlags) | KIO::HideProgressInfo; KIO::Job *job = nullptr; switch (m_renameMode) { default: case eRenameMode_Rename: case eRenameMode_Move: job = KIO::file_move(dstUrl, (*m_files)[i].srcUrl(), -1, flags); break; case eRenameMode_Link: // In case of link delete created file job = KIO::file_delete(dstUrl, KIO::HideProgressInfo); break; case eRenameMode_Copy: // no undo possible // TODO: Maybe we should delete the created files break; } if (job) { KJobWidgets::setWindow(job, p); if (!job->exec()) { p->error(i18n("Error during undoing %1", dstUrl.toDisplayString(QUrl::PreferLocalFile))); (*m_files)[i].setError(job->error()); errors++; } } } if (errors > 0) { p->warning(i18np("%1 error occurred.", "%1 errors occurred.", errors)); } p->print(i18n("KRename finished the undo process."), "krename"); p->print(i18n("Press close to quit.")); p->renamingDone(false, false, this, errors); // do not allow undo from undo } QString BatchRenamer::processBrackets(QString text, int *length, const QString &oldname, int index) { int pos = 0; QString token; QString result; *length = 0; // MSG: qDebug("processBrackets: %s\n", text.toUtf8().data() ); while ((pos = getNextToken(text, token, pos)) != -1) { if (token == "[") { int localLength = 0; QString substitute = processBrackets(text.right(text.length() - pos), &localLength, oldname, index); text.replace(pos - 1, localLength, substitute); // MSG: qDebug("substituted: %s\n", text.toUtf8().data() ); // Assure that *length does not become negative, // this will cause infinite loops if (localLength < substitute.length()) { *length += localLength; } else { *length += (localLength - substitute.length()); } } else if (token == "]") { // Done with this token // MSG: qDebug("END: %s\n", text.left( pos - 1 ).toUtf8().data() ); result = findToken(oldname, text.left(pos - 1), index); *length += pos + 1; break; } } // MSG: qDebug("processedBrackets: %s\n", result.toUtf8().data() ); /* if( pos != -1 ) { result = findToken( oldname, text.left( pos - 1 ), index ); *length = pos+1; // skip any closing bracket } */ return result; } QString BatchRenamer::processNumber(int length, const QString &appendix) { tCounterValues countervalues; countervalues.start = m_index; countervalues.step = m_step; if (!appendix.isEmpty()) { bool ok = false; int tmp = appendix.section(';', 0, 0).toInt(&ok); // first section = start index if (ok) { countervalues.start = tmp; } tmp = appendix.section(';', 1, 1).toInt(&ok); // second section = stepping if (ok) { countervalues.step = tmp; } } if ((signed int)m_counters.count() <= m_counter_index) { countervalues.value = countervalues.start - countervalues.step; // other wise the counter would start at: // start + step instead of start m_counters.append(countervalues); } do { m_counters[m_counter_index].value += m_counters[m_counter_index].step; } while (m_skip.contains(m_counters[m_counter_index].value)); QString number; number.sprintf("%0*i", length, m_counters[m_counter_index].value); ++m_counter_index; return number; } QString BatchRenamer::processString(QString text, const QString &originalName, int index, bool doFindReplace) { QString oldname = originalName; doEscape(oldname); // Parse into tokens int pos = 0; QString token; while ((pos = getNextToken(text, token, pos)) != -1) { // Handle simple tokens if (token == "$") { text.replace(pos - 1, token.length(), oldname); pos += oldname.length() - 1; } else if (token == "%") { text.replace(pos - 1, token.length(), oldname.toLower()); pos += oldname.length() - 1; } else if (token == "&") { text.replace(pos - 1, token.length(), oldname.toUpper()); pos += oldname.length() - 1; } else if (token == "*") { QString tmp = capitalize(oldname); text.replace(pos - 1, token.length(), tmp); pos += tmp.length() - 1; } else if (token == "[") { int length = 0; QString substitute = processBrackets(text.right(text.length() - pos), &length, oldname, index); text.replace(pos - 1, length, substitute); if (substitute.length() > 0) { pos += substitute.length() - 1; } } else if (token == "]") { // Ignore } else if (token == "#") { int curPos = pos; int count = 1; while (text[curPos] == '#') { ++curPos; count++; } int length = curPos - pos + 1; int appendixLength = 0; QString appendix; if (text[curPos] == '{') { int appendixPos = curPos + 1; QString appendixToken; while ((appendixPos = getNextToken(text, appendixToken, appendixPos)) != -1) { if (appendixToken == "}") { break; } } if (appendixPos == -1) { // Do go into endless loop if token is not completed correctly appendixPos = text.length(); } // -2 because we have to go, before the current found token appendix = text.mid(curPos + 1, appendixPos - curPos - 2); appendixLength = appendixPos - curPos; } QString number = processNumber(count, appendix); text.replace(pos - 1, (length + appendixLength), number); if (number.length() > 0) { pos += number.length() - 1; } } } //text = parsePlugins( i, text, TYPE_TOKEN ); /* * Replace after Plugins ! * Replace should be the last the * before re-escaping tokens ! */ if (doFindReplace) { text = findReplace(text, originalName, index); } text = unEscape(text); return text; } QString BatchRenamer::capitalize(const QString &text) const { QString tmp = text.toLower(); if (tmp[0].isLetter()) { tmp[0] = tmp[0].toUpper(); } for (int i = 0; i < tmp.length(); i++) if (tmp[i + 1].isLetter() && !tmp[i].isLetter() && tmp[i] != '\'' && tmp[i] != '?' && tmp[i] != '`') { tmp[i + 1] = tmp[i + 1].toUpper(); } return tmp; } QString BatchRenamer::executePlugin(int index, const QString &filenameOrPath, int type, int &errorCount, ProgressDialog *p) { const QList &plugins = PluginLoader::Instance()->plugins(); QList::const_iterator it = plugins.begin(); errorCount = 0; QString ret = filenameOrPath; while (it != plugins.end()) { if ((*it)->isEnabled() && ((*it)->type() & type)) { // Every plugin should use the return value of the previous as the new filename to work on ret = (*it)->processFile(this, index, ret, static_cast(type)); if (type == ePluginType_File) { if (! ret.isEmpty()) { // An error occurred -> report it if (p != nullptr) { p->error(ret); } ++errorCount; } ret = filenameOrPath; } } ++it; } return ret; } void BatchRenamer::work(ProgressDialog *) { #if 0 // TODO: use CopyJob here FileOperation fop; QFile *fundo(NULL); QTextStream *tundo(NULL); if (undo) { // Create header for undo script fundo = new QFile(m_undoScript); if (fundo->open(IO_WriteOnly)) { tundo = new QTextStream(fundo); writeUndoScript(tundo); } else { undo = false; p->error(i18n("Cannot create undo script: %1", fundo->name())); delete fundo; } } int error = 0; RenamedList *renamedFiles = new RenamedList[m_files.count()]; p->setProgressTotalSteps(m_files.count() + 1); /* * Give the user some information... */ if (m_mode == COPY) { p->print(i18n("Files will be copied to: %1", m_files[0].dst.directory)); } else if (m_mode == MOVE) { p->print(i18n("Files will be moved to: %1", m_files[0].dst.directory)); } else if (m_mode == LINK) { p->print(i18n("Symbolic links will be created in: %1", m_files[0].dst.directory)); } else if (m_mode == RENAME) { p->print(i18n("Input files will be renamed.")); } unsigned int i; for (i = 0; i < m_files.count(); i++) { p->setProgress(i + 1); if (p->wasCancelled()) { break; } KURL src = m_files[i].src.url; KURL dst = m_files[i].dst.url; dst.setPath(m_files[i].dst.name); renamedFiles[i].src = src; renamedFiles[i].dst = dst; renamedFiles[i].dir = m_files[i].dir; FileOperation fop; if (!fop.start(src, dst, m_mode, overwrite)) { p->error(fop.error()); renamedFiles[i].error = true; error++; continue; } else { renamedFiles[i].error = false; } // TODO: overwriting of files! /* * The renamed file should be on its correct location now, * so that we can call the last plugins (e.g. for changing permissions) * * Remember, the token argument is the filename for this type of plugins! * * If the return value is not empty an error has occurred! * The plugin should return an error message in this case! */ QString eplug = parsePlugins(i, QString::null, TYPE_FINAL_FILE); if (!eplug.isEmpty()) { p->error(eplug); error++; } /* Create the undo script now */ if (undo) if (dst.isLocalFile() && src.isLocalFile()) { // Plugins ??? (*tundo) << "echo \"" << dst.fileName() << " -> " << src.fileName() << "\"" << endl; (*tundo) << "mv -f \"" << m_files[i].dst.name << "\" \"" << m_files[i].src.name << "\"" << endl; } else { p->warning(i18n("Undo is not possible for remote file: %1", dst.prettyURL())); } } if (!p->wasCancelled()) { QPtrListIterator it(plug->libs); for (; it.current(); ++it) { if ((*it)->usePlugin) { (*it)->plugin->finished(); } } } const QString m = i18n("Renamed %1 files successfully.", i - error); (i - error) ? p->print(m) : p->warning(m); if (error > 0) { p->warning(i18np("%1 error occurred.", "%1 errors occurred.", error)); } p->print(i18n("Elapsed time: %1 seconds", t.elapsed() / 1000), "kalarm"); p->print(i18n("KRename finished the renaming process."), "krename"); p->print(i18n("Press close to quit.")); p->setRenamedFiles(renamedFiles, m_files.count()); if (undo) { (*tundo) << endl << "echo \"Finished undoing " << m_files.count() << " actions.\"" << endl; delete tundo; fundo->close(); // Make fundo exuteable if (chmod((const char *)m_undoScript, (unsigned int) S_IRUSR | S_IWUSR | S_IXUSR)) { p->error(i18n("Cannot set executable bit on undo script.")); } delete fundo; } p->done(error, i - error, m_mode == MOVE || m_mode == RENAME); m_files.clear(); delete []renamedFiles; delete this; #endif // 0 } const QUrl BatchRenamer::buildDestinationUrl(const KRenameFile &file) const { QUrl dstUrl = file.dstUrl(); QString directory = file.dstDirectory(); QString filename = file.dstFilename(); QString extension = file.dstExtension(); QString manual = file.manualChanges(); if (!extension.isEmpty()) { filename += '.'; filename += extension; } if (!manual.isNull()) { filename = manual; } dstUrl.setPath(directory + '/' + filename); return dstUrl; } void BatchRenamer::escape(QString &text, const QString &token, const QString &sequence) { text.replace(token, sequence); } QString &BatchRenamer::doEscape(QString &text) { BatchRenamer::escape(text, "\\", "\\\\"); BatchRenamer::escape(text, "&", "\\&"); BatchRenamer::escape(text, "$", "\\$"); BatchRenamer::escape(text, "%", "\\%"); BatchRenamer::escape(text, "#", "\\#"); BatchRenamer::escape(text, "[", "\\["); BatchRenamer::escape(text, "]", "\\]"); BatchRenamer::escape(text, "/", "\\/"); BatchRenamer::escape(text, "{", "\\{"); BatchRenamer::escape(text, "}", "\\}"); BatchRenamer::escape(text, "*", "\\*"); return text; } QString &BatchRenamer::unEscape(QString &text) { BatchRenamer::escape(text, "\\\\", "\\"); BatchRenamer::escape(text, "\\&", "&"); BatchRenamer::escape(text, "\\$", "$"); BatchRenamer::escape(text, "\\%", "%"); BatchRenamer::escape(text, "\\#", "#"); BatchRenamer::escape(text, "\\[", "["); BatchRenamer::escape(text, "\\]", "]"); // %252f == /, it seems that filenames on unix cannot contain // a /. So I use %252f, at least konqui displays it correctly // this was needed, so that plugins that return a slash do not cause errors BatchRenamer::escape(text, "\\/", "%2f"); BatchRenamer::escape(text, "\\{", "{"); BatchRenamer::escape(text, "\\}", "}"); BatchRenamer::escape(text, "\\*", "*"); return text; } QString BatchRenamer::processToken(QString token, QString oldname, int i) { QString tmp; /* * Call here all functions that handle * arguments in brackets. */ tmp = findPartStrings(oldname, token); if (!tmp.isEmpty()) { return tmp; } tmp = findDirName(token, (*m_files)[i].srcDirectory()); if (!tmp.isEmpty()) { return tmp; } tmp = findLength(token, (*m_files)[i].srcFilename()); if (!tmp.isEmpty()) { return tmp; } tmp = findTrimmed(token, (*m_files)[i].srcFilename(), i); if (!tmp.isEmpty()) { return tmp; } tmp = findDirSep(token, (*m_files)[i].srcFilename()); if (!tmp.isEmpty()) { return tmp; } Plugin *p = PluginLoader::Instance()->findPlugin(token); if (p) { tmp = p->processFile(this, i, token, ePluginType_Token); if (!tmp.isNull()) { doEscape(tmp); return tmp; } } /* * Maybe I should remove this! * KRename simply ignores unknown tokens! * Useful for the MP3 Plugin! */ return QString(); } QString BatchRenamer::findToken(const QString &oldname, QString token, int i) { enum conversion { LOWER, UPPER, MIXED, STAR, NONE, EMPTY, NUMBER }; unsigned int numwidth = 0; conversion c = EMPTY; if (!token.left(1).compare("$")) { c = NONE; } else if (!token.left(1).compare("%")) { c = LOWER; } else if (!token.left(1).compare("&")) { c = UPPER; } else if (!token.left(1).compare("")) { c = MIXED; } else if (!token.left(1).compare("*")) { c = STAR; } else if (!token.left(1).compare("#")) { while (!token.left(1).compare("#")) { token.remove(0, 1); ++numwidth; } c = NUMBER; } if (c != EMPTY && c != NUMBER) { token.remove(0, 1); } QString save = token; token = processToken(token, oldname, i); switch (c) { case LOWER: token = token.toLower(); break; case UPPER: token = token.toUpper(); break; case MIXED: token = token.toLower(); token.replace(0, 1, token[0].toUpper()); break; case STAR: token = capitalize(token); break; case NUMBER: { bool b = false; int n = token.toInt(&b); if (b) { token = token.sprintf("%0*i", numwidth, n); } } break; default: break; } return token; } QString BatchRenamer::findPartStrings(QString oldname, QString token) { QString first, second; int pos = -1; // MSG: qDebug("PART: %s", token.toUtf8().data() ); // parse things like [2;4{[dirname]}] if (token.count('{') >= 1 && token.count('}') >= 1) { int pos = token.indexOf('{'); oldname = token.mid(pos + 1, token.lastIndexOf('}') - pos - 1); token = token.left(pos); } if (token.contains('-')) { pos = token.indexOf('-', 0); first = token.left(pos); // ------- Code OK ^ ! second = token.mid(pos + 1, token.length()); // version < 1.7 // return oldname.mid( first.toInt()-1, second.toInt()-first.toInt() +1 ); // version > 1.7 //return oldname.mid( first.toInt()-1, second.toInt()-first.toInt() ); // version > 1.8 bool ok; int sec = second.toInt(&ok); if (!ok || sec == 0) { sec = oldname.length(); } /* * x should not be larger than the old name * and not smaller than zero. */ int x = sec - first.toInt(&ok); // if first is no number, but for example length, we return here so that findLength can do its job if (!ok) { return QString(); } if (x > (signed int)oldname.length() || x < 0) { x = oldname.length() - first.toInt(); } /* * if I would comment my code I would understand this line :) * without this line, there is sometimes the last letter * of a filename missing. */ if (x != -1) { x++; } return oldname.mid(first.toInt() - 1, x); } else if (token.contains(';')) { pos = token.indexOf(';', 0); first = token.left(pos); second = token.mid(pos + 1, token.length()); return oldname.mid(first.toInt() - 1, second.toInt()); } else { bool ok = false; int number = token.toInt(&ok); if (ok && (number <= (signed int)oldname.length() && number > 0)) { return QString(oldname[ number - 1 ]); } else { return QString(); } } } QString BatchRenamer::findDirName(QString token, QString path) { if (token.toLower().startsWith(QLatin1String("dirname"))) { if (path.right(1) == "/") { path = path.left(path.length() - 1); } int recursion = 1; if (token.length() > 7) { token = token.right(token.length() - 7); recursion = token.count('.'); if (recursion != (signed int)token.length()) { return QString(); } recursion++; } return path.section("/", recursion * -1, recursion * -1); } return QString(); } QString BatchRenamer::findDirSep(const QString &token, const QString &path) { if (token.toLower() == "dirsep") { return "/"; } return QString(); } QString BatchRenamer::findLength(const QString &token, const QString &name) { if (token.toLower().startsWith(QLatin1String("length"))) { int minus = 0; if (token.length() > 6 && token[6] == '-') { bool n = false; minus = token.mid(7, token.length() - 7).toInt(&n); if (!n) { minus = 0; } } return QString::number(name.length() - minus); } return QString(); } QString BatchRenamer::findTrimmed(const QString &token, const QString &name, int index) { if (token.toLower().startsWith(QLatin1String("trimmed"))) { if (token.contains(';')) { QString processed = processString( token.section(';', 1, 1), name, index).trimmed(); if (processed.isNull()) { return name.trimmed(); } else { return processed.trimmed(); } } else { return name.trimmed(); } } return QString(); } QString BatchRenamer::findReplace(const QString &text, const QString &origFilename, int index) { QList::const_iterator it = m_replace.constBegin(); QString t(text); while (it != m_replace.constEnd()) { QString find((*it).find); // Call for each element in replace strings doReplace with correct values t = doReplace(t, unEscape(find), (*it).replace, (*it).reg, (*it).doProcessTokens, origFilename, index); ++it; } return t; } QString BatchRenamer::doReplace(const QString &text, const QString &find, const QString &replace, bool reg, bool doProcessTokens, const QString &origFilename, int index) { QString t(text); if (!reg) { QString escaped = find; escaped = doEscape(escaped); // we use the escaped text here because the user might want // to find a "&" and replace it t.replace(escaped, replace); } else { // no doEscape() here for the regexp, because it would destroy our regular expression // other wise we will not find stuff like $, [ in the text t = unEscape(t).replace(QRegExp(find), replace); t = doEscape(t); } if (doProcessTokens) { t = processString(unEscape(t), origFilename, index, false); } return t; } void BatchRenamer::writeUndoScript(QTextStream *t) { // write header comments (*t) << "#!/bin/sh" << endl << "# KRename Undo Script" << endl << "#" << endl << "# KRename was written by:" << endl << "# Dominik Seichter " << endl << "# http://krename.sourceforge.net" << endl << "#" << endl << "# Script generated by KRename Version: " << VERSION << endl << endl << "# This script must be started with the option --krename to work!" << endl; // write functions: (*t) << "echo \"KRename Undo Script\"" << endl << "echo \"http://krename.sourceforge.net\"" << endl << "echo \"\"" << endl; (*t) << "if test --krename = $1 ; then" << endl << " echo \"\"" << endl << "else" << endl << " echo \"You have to start this script\"" << endl << " echo \"with the command line option\"" << endl << " echo \"--krename\"" << endl << " echo \"to undo a rename operation.\"" << endl << " exit" << endl << "fi" << endl; } -void BatchRenamer::createMissingSubDirs(const KRenameFile &file, ProgressDialog *dialog) +void BatchRenamer::createMissingSubDirs(const QUrl &destUrl, ProgressDialog *dialog) { - QUrl url = file.dstUrl().adjusted(QUrl::RemoveFilename); + QUrl url = destUrl.adjusted(QUrl::RemoveFilename); if (url.isEmpty()) { return; } KIO::MkpathJob *job = KIO::mkpath(url); KJobWidgets::setWindow(job, dialog); if (!job->exec()) { dialog->error(i18n("Cannot create directory %1: %2", url.toDisplayString(QUrl::PreferLocalFile), job->errorString())); } } void BatchRenamer::findCounterReset(int i) { if ((*m_files)[i - 1].srcDirectory() != (*m_files)[i].srcDirectory()) for (int z = 0; z < (int)m_counters.count(); z++) { m_counters[z].value = m_counters[z].start - m_counters[z].step; } } diff --git a/src/batchrenamer.h b/src/batchrenamer.h index 337d357..e8fa0b8 100644 --- a/src/batchrenamer.h +++ b/src/batchrenamer.h @@ -1,457 +1,457 @@ /*************************************************************************** batchrenamer.h - description ------------------- begin : Sat Aug 18 2001 copyright : (C) 2001 by Dominik Seichter email : domseichter@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef BATCHRENAMER_H #define BATCHRENAMER_H #include #include #include "krenamefile.h" class QFile; class QProgressDialog; class QString; class QTextStream; typedef struct __tag_tCounterValues { int value; // current value of this counter int start; // start value of this counter (for findResetCounter) int step; // stepping value of this counter; } tCounterValues; /** A structure describing a string or regular * expression that is to be found in the final/resulting * filename and to be replaced with another string. */ typedef struct __tag_TReplaceItem { QString find; ///< Text to replace QString replace; ///< Replace with bool reg; ///< is it a reg expression ? bool doProcessTokens; ///< Process tokens in result } TReplaceItem; /** An enum to set the renaming mode of KRename */ enum ERenameMode { eRenameMode_Rename, ///< All files are renamed in place eRenameMode_Move, ///< All files are moved to a new directory and renamed eRenameMode_Copy, ///< Only copies of the files are renamed eRenameMode_Link ///< Symbolic links are created and renamed }; class QObject; class ProgressDialog; /** This is the core class for renaming. * * It transforms the filenames according to * the users settings using custom functions * and external plugins. * Also the actual renaming, copying or moving * of the files is done by this class * * @author Dominik Seichter */ class BatchRenamer : public QObject { Q_OBJECT public: BatchRenamer(); ~BatchRenamer(); /** Sets the list of files * which contains all filenames which should be transformed. * * The renamed filenames are stored in this list, too,. * * @param list a list of KRenameFile objects */ inline void setFiles(KRenameFile::List *list); /** Get access to the list of files used for renaming. * @returns the list of files or NULL if none was set. */ inline const KRenameFile::List *files() const; /** * @returns the current renaming mode */ inline ERenameMode renameMode() const; /** * @returns the current start index for counters */ inline int numberStartIndex() const; /** * @returns the stepping for counters */ inline int numberStepping() const; /** * @returns if counters are reset on new directories */ inline int numberReset() const; /** * @returns the list of numbers that are skipped during renaming */ inline QList numberSkipList() const; /** Does the actuall renaming, * transforming all source filenames in the file list * to the new destination filenames. * * No actuall renaming is done, only the new filenames * are calculated. */ void processFilenames(); /** Process all files * * processFilenames has to be called before * * All files will be renamed according to the users settings. * * Output will be reported through a progress dialog * * @param p use this dialog to report progress to the user */ void processFiles(ProgressDialog *p); /** undo all files * * processFiles has to be called before * * A previous renaming operation will be undone. * * Output will be reported through a progress dialog * * @param p use this dialog to report progress to the user */ void undoFiles(ProgressDialog *p); /** Build the destination url from a KRenameFile * * @param file a KRenameFile * @returns a valid QUrl */ const QUrl buildDestinationUrl(const KRenameFile &file) const; inline void setUndoScript(const QString &t) { m_undoScript = t; } inline void setUndo(bool b) { undo = b; } inline void setReplaceList(const QList &r) { m_replace = r; } inline const QList &replaceList() const { return m_replace; } inline void setMode(int m) { m_mode = m; } inline int mode() const { return m_mode; } QString findToken(const QString &oldname, QString token, int i); QString findPartStrings(QString oldname, QString token); static QString findDirName(QString token, QString path); /** * Replace the token [dirsep] with a slash "/". * This token is useful to create directories from within regular expressions. */ static QString findDirSep(const QString &token, const QString &path); static QString &doEscape(QString &text); static QString &unEscape(QString &text); static void escape(QString &text, const QString &token, const QString &sequence); /** Capitalize a string. * * Used to implement the * token. * * @param a text string * @return a capitalized version of this string (every first letter is a capital letter now) */ QString capitalize(const QString &text) const; /** Handle the [length] tokens * * @param token a token found in square brackets * @param name the filename of the current file * * @return QString::null if no length token was found or the a new string */ QString findLength(const QString &token, const QString &name); /** Handle the [trimmed] token * * @param token a token found in square brackets * @param name the filename of the current file * @param index index of the current file * * @return QString::null if no length token was found or the a new string */ QString findTrimmed(const QString &token, const QString &name, int index); QString processString(QString text, const QString &originalName, int i, bool doFindReplace = true); QString processBrackets(QString text, int *length, const QString &oldname, int index); QString processNumber(int length, const QString &appendix); QString processToken(QString token, QString oldname, int i); public Q_SLOTS: /** Sets the current mode of renaming. * KRename can rename files, move them while * renaming to another directory, rename copies * or create renamed sym-links. * * This mode specifies what should be done with the files. * * @param mode the renaming mode. */ inline void setRenameMode(ERenameMode mode); /** Sets the template for the filename that is used * to transform the filename to its final representation. * * @param t the new template */ inline void setFilenameTemplate(const QString &t); /** Sets the template for the filename that is used * to transform the filename to its final representation. * * @param t the new template */ inline void setExtensionTemplate(const QString &t); /** Set the start index for the basic counters * which do not specify an own start index in their * appendiy (e.g. ###{7}, means 7 is the start index * * @param i start index */ inline void setNumberStartIndex(int i) { m_index = i; } /** Set the stepping for the basic counters * which do not specify an own stepping in their * appendiy (e.g. ###{1,2}, means 2 is the stepping * * @param s stepping */ inline void setNumberStepping(int s) { m_step = s; } /** Sets whether all counters should be reset for new * directories * * @param r if true counters will be reset */ inline void setNumberReset(bool r) { m_reset = r; } /** Sets the list of numbers that are skipped by counters * * @param s a list of numbers that is skipped */ inline void setNumberSkipList(const QList &s) { m_skip = s; } /** Sets if existing files maybe overwritten during renaming * * @param overwrite if true existing files will be overwritten */ inline void setOverwriteExistingFiles(bool overwrite) { m_overwrite = overwrite; } /** Sets the destination url (a directory) for copy, move and link operations * * @param url destination directory */ inline void setDestinationDir(const QUrl &url) { m_destination = url; } private: /** Do find and replace on the final resulting filename. * * \param text the new final filename with all other changes applied. * * \returns the new filename with all find and replace being done. * * \see m_replace */ QString findReplace(const QString &text, const QString &origFilename, int index); /** * Replace one string (which might be a regular expression) in the final filename * with another string and return a new filename. * * \param text the new final filename with all other changes applied. * \param find the string or regular expression to find * \param replace replace a matched string with this value * \param reg if true treat find as regular expression * \param doProcessTokens process tokens in replaced results * \param originalName original filename for replacing tokens * \param index current index * * \returns the new filename with find and replace being done. */ QString doReplace(const QString &text, const QString &find, const QString &replace, bool reg, bool doProcessTokens, const QString &origFilename, int index); private: /** Execute all plugins of a certain type * * @param index the current index * @param filenameOrPath the current filename or path * @param type the type of the plugins to run * @param errorCount the number of errors will be written to this value * @param p dialog for error reporting (maybe NULL) * * @returns either a new filename or an error message (depends on plugin type) */ QString executePlugin(int index, const QString &filenameOrPath, int type, int &errorCount, ProgressDialog *p); void work(ProgressDialog *p); void writeUndoScript(QTextStream *t); /** * Parse a new filename and create missing subdirectories. * * This will look for '/' and create all not existing directories * - * @param file to check for not existing directories - * @param p ProgressDialog for error reporting + * @param destUrl to check for not existing directories + * @param dialog ProgressDialog for error reporting */ - void createMissingSubDirs(const KRenameFile &file, ProgressDialog *dialog); + void createMissingSubDirs(const QUrl &destUrl, ProgressDialog *dialog); /** resets all counters to there start value if the directory name at @p i * in m_files changes. * The caller has to check m_reset before calling this function. */ void findCounterReset(int i); QString text; // template QString extext; // Extension template QString m_undoScript; // Filename of undoscript bool undo; // create an undo script bool m_reset; // reset counter on new directories int m_mode; // renaming mode QList m_skip; // Numbers to skip // a is used in find number and // required for skipping. int m_counter_index; int m_index; // index for numbers int m_step; // step for numbers QList m_counters; private: KRenameFile::List *m_files; ///< The list of files to rename and the resulting renamed filenames ERenameMode m_renameMode; ///< The rename mode specifies if files are renamed, copied or moved (or linked) bool m_overwrite; ///< Overwrite existing files QUrl m_destination; ///< Destination directory for copy, move and link QList m_replace; ///< List of strings for find and replace protected: QFile *f; QTime t; QProgressDialog *progress; }; void BatchRenamer::setFiles(KRenameFile::List *list) { m_files = list; } const KRenameFile::List *BatchRenamer::files() const { return m_files; } void BatchRenamer::setRenameMode(ERenameMode mode) { m_renameMode = mode; } ERenameMode BatchRenamer::renameMode() const { return m_renameMode; } void BatchRenamer::setFilenameTemplate(const QString &t) { text = t; } void BatchRenamer::setExtensionTemplate(const QString &t) { extext = t; } int BatchRenamer::numberStartIndex() const { return m_index; } int BatchRenamer::numberStepping() const { return m_step; } int BatchRenamer::numberReset() const { return m_reset; } QList BatchRenamer::numberSkipList() const { return m_skip; } #endif diff --git a/src/datetimeplugin.cpp b/src/datetimeplugin.cpp index 02991db..b08d171 100644 --- a/src/datetimeplugin.cpp +++ b/src/datetimeplugin.cpp @@ -1,138 +1,138 @@ /*************************************************************************** datetimeplugin.cpp - description ------------------- begin : Sun Mar 9 2008 copyright : (C) 2002 by Dominik Seichter email : domseichter@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ -#ifndef Q_OS_WIN #include "datetimeplugin.h" +#ifndef Q_OS_WIN #include #include "ui_datetimepluginwidget.h" #include #include #include #include // OS includes #include #include #include #include #include #include DateTimePlugin::DateTimePlugin(PluginLoader *loader) : QObject(nullptr), Plugin(loader) { m_widget = new Ui::DateTimePluginWidget(); } DateTimePlugin::~DateTimePlugin() { delete m_widget; } const QString DateTimePlugin::name() const { return i18n("Date & Time Plugin"); } const QPixmap DateTimePlugin::icon() const { return KIconLoader::global()->loadIcon("chronometer", KIconLoader::NoGroup, KIconLoader::SizeSmall); } QString DateTimePlugin::processFile(BatchRenamer *, int, const QString &filenameOrToken, EPluginType) { const QString &filename = filenameOrToken; bool bModification = m_widget->checkModification->isChecked(); bool bAccess = m_widget->checkAccess->isChecked(); QDate date = m_widget->datepicker->date(); QTime time(m_widget->spinHour->value(), m_widget->spinMinute->value(), m_widget->spinSecond->value()); if (!QUrl(filename).isLocalFile()) { return i18n("DateTimePlugin works only with local files. %1 is a remote file.", filename); } if (bModification || bAccess) { return changeDateTime(filename, bModification, bAccess, date, time); } return QString(); } void DateTimePlugin::createUI(QWidget *parent) const { m_widget->setupUi(parent); connect(m_widget->buttonCurrent, &QPushButton::clicked, this, &DateTimePlugin::slotGetCurrentTime); } void DateTimePlugin::slotGetCurrentTime() { m_widget->spinHour->setValue(QTime::currentTime().hour()); m_widget->spinMinute->setValue(QTime::currentTime().minute()); m_widget->spinSecond->setValue(QTime::currentTime().second()); m_widget->datepicker->setDate(QDate::currentDate()); } QString DateTimePlugin::changeDateTime(const QString &filename, bool bModification, bool bAccess, const QDate &date, const QTime &time) { // Initialze fields struct tm tmp; tmp.tm_mday = date.day(); tmp.tm_mon = date.month() - 1; tmp.tm_year = date.year() - 1900; tmp.tm_hour = time.hour(); tmp.tm_min = time.minute(); tmp.tm_sec = time.second(); tmp.tm_isdst = -1; // Create time time_t ti; ti = mktime(&tmp); if (ti == -1) { return i18n("Cannot change date of file %1. (Cannot mktime)", filename); } // Get current values QT_STATBUF st; if (QT_STAT(filename.toUtf8().data(), &st) == -1) { return i18n("Cannot change date of file %1. (Cannot stat the file)", filename); } // Fill structure; struct utimbuf buf; buf.actime = (bAccess ? ti : st.st_atime); buf.modtime = (bModification ? ti : st.st_mtime); if (utime(filename.toUtf8().data(), &buf) != 0) { return i18n("Cannot change date of file %1. (utime failed)", filename); } return QString(); } #endif // Q_OS_WIN diff --git a/src/datetimeplugin.h b/src/datetimeplugin.h index e713fa1..ebe46ca 100644 --- a/src/datetimeplugin.h +++ b/src/datetimeplugin.h @@ -1,157 +1,162 @@ /*************************************************************************** datetimeplugin.h - description ------------------- begin : Sun Mar 9 2008 copyright : (C) 2002 by Dominik Seichter email : domseichter@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef DATE_TIME_PLUGIN_H #define DATE_TIME_PLUGIN_H +#include +#ifndef Q_OS_WIN + #include "plugin.h" #include namespace Ui { class DateTimePluginWidget; }; class QDate; class QTime; /** This is the abstract interface that has to be implemented * by all KRename plugins. */ class DateTimePlugin : public QObject, public Plugin { Q_OBJECT public: explicit DateTimePlugin(PluginLoader *loader); virtual ~DateTimePlugin(); /** * @returns a name of the plugin that can be displayed * to the user. This name should be internationalized. */ virtual const QString name() const; /** * Determines the type of the plugin. * Different enum values may be or'ed together. * * @returns the type of the plugin. */ inline virtual int type() const; /** * @returns an icon for this plugin. */ virtual const QPixmap icon() const; /** * @returns true if this plugins is always enabled * * Warning: If you return true here, the user has no possibility to * disable this plugin. */ inline virtual bool alwaysEnabled() const; /** * This function is the core of your plugin. * * It does the actual processing of a file, filename or token depending of the type * of your plugin. * * \see type() * * @param b the parent BatchRenamer instance calling this plugin * @param index the index of the current file (i.e. the first file has index 0, * the second file to be renamed has index 1 ....) * @param filenameOrToken this parameter depends on the type of your plugin. * If type is ePluginType_File, this is the absolute path * or URL to the renamed file. * If type is ePluginType_Filename, this is the filename * (without path) as created by KRename. * If type is ePluginType_Token, this is the contents of a token * in brackets. If your plugin supports the token [example], * KRename will pass the strign "example" to your method. * @param eCurrentType the current type of plugin that is requested (for plugins that support more than one type) * * @returns the result of the function, depending on type(). * @returns QString::null if this plugin has nothing to do. * @returns A new filename if type is ePluginType_Filename * @returns the value of the token if type is ePluginType_Token * @returns an error message or QString::null if type is ePluginType_File */ virtual QString processFile(BatchRenamer *b, int index, const QString &filenameOrToken, EPluginType eCurrentType); /** Get a list of all tokens supported by this plugin. * * If the token type != ePluginType_Token you have to return an empty list * * @returns a list of all supported tokens. The returned strings will be treated * as regular expressions to find a plugin which supports a token. */ inline virtual const QStringList &supportedTokens() const; /** Returns help descriptions for the supported tokens * * The returned stringlist contains strings that are the tokens * and the description separated by ;; * * @returns a stringlist containing help on the supported tokens */ inline virtual const QStringList &help() const; /** Create a user interface for this plugin * * @param parent the parent widget of this plugin */ virtual void createUI(QWidget *parent) const; private Q_SLOTS: void slotGetCurrentTime(); private: QString changeDateTime(const QString &filename, bool bModification, bool bAccess, const QDate &date, const QTime &time); private: Ui::DateTimePluginWidget *m_widget; QStringList m_tmp; ///< Dummy empty list so that we can return a reference for supported tokens and help }; inline int DateTimePlugin::type() const { return ePluginType_File; } inline bool DateTimePlugin::alwaysEnabled() const { return false; } inline const QStringList &DateTimePlugin::supportedTokens() const { return m_tmp; } inline const QStringList &DateTimePlugin::help() const { return m_tmp; } +#endif // Q_OS_WIN + #endif /* DATE_TIME_PLUGIN_H */ diff --git a/src/main.cpp b/src/main.cpp index a629460..60faf58 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,164 +1,165 @@ /*************************************************************************** main.cpp - description ------------------- begin : Die Mai 15 15:34:19 CEST 2001 copyright : (C) 2001 by Dominik Seichter email : domseichter@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your2192 option) any later version. * * * ***************************************************************************/ // Qt includes #include +#include #include // KDE includes #include #include #include #include // Own includes #include "krenameimpl.h" // OS includes #ifndef Q_OS_WIN #include #endif #include #include #include #include #include #include #include #include "../config-krename.h" int main(int argc, char *argv[]) { KLocalizedString::setApplicationDomain("krename"); QApplication app(argc, argv); KCrash::initialize(); KAboutData aboutData("krename", i18n("KRename"), VERSION); aboutData.setShortDescription(i18n( "KRename is a batch file renamer which can rename a " "list of files based on a set of expressions.")); aboutData.setOtherText(i18n( "If you like KRename you may want to support it. " "Testing, bug fixes and feature requests are as welcome " "as financial support (everybody needs money ;). See help files for details.")); aboutData.setLicense(KAboutLicense::GPL_V3); aboutData.setCopyrightStatement(i18n("(c) 2001-2012, Dominik Seichter\n")); aboutData.setHomepage("http://www.krename.net"); aboutData.addAuthor(i18n("Heiko Becker"), i18n("Current maintainer"), "heirecka@exherbo.org"); aboutData.addAuthor(i18n("Dominik Seichter"), i18n("Developer and former maintainer"), "domseichter@web.de", "http://www.krename.net"); aboutData.addAuthor(i18n("Stefan \"Stonki\" Onken"), i18n("Website, testing, very good ideas and keeping me coding!"), "support@stonki.de", "http://www.stonki.de"); aboutData.addCredit(i18n("Arpad Biro"), i18n("Helped to fix style guide issues and made improvements to user messages."), "biro.arpad@gmail.com"); aboutData.addCredit(i18n("Trevor Semeniuk"), i18n("Thanks to him for creating RedHat 7.x packages and some other help."), "semeniuk@ee.ualberta.ca", "http://www.semeniuk.net"); aboutData.addCredit(i18n("Groult Richard"), i18n("Fixed a bug with startIndex and added the BatchRenamer class\n" "to his excellent image viewer showimg."), "rgroult@jalix.org", "http://ric.jalix.org/"); aboutData.addCredit(i18n("Michael Elvers"), i18n("Fixed a bug that caused krename not closing open files."), "m_elvers@yahoo.com", "http://come.to/melvers"); aboutData.addCredit(i18n("Andreas Pour"), i18n("Thanks for his great job at apps.kde.com and help with contributing krename to apps.kde.com."), "pour@mieterra.com", "http://apps.kde.com"); aboutData.addCredit(i18n("Charles Samuels"), i18n("Thanks for noatun and the ID3/Ogg Tag code is based on his noatun modules."), "charles@kde.org", "http://noatun.kde.org/"); aboutData.addCredit(i18n("Franz Schmid"), i18n("Gave me a good start into writing plugins with his application scribus."), "Franz.Schmid@altmuehlnet.de", "http://web2.altmuehlnet.de/fschmid/index.html"); aboutData.addCredit(i18n("Rolf Magnus"), i18n("Parts of the PNG support are copied from his KFile plugin for png support."), "ramagnus@kde.org"); aboutData.addCredit(i18n("Michael v.Ostheim"), i18n("Created the Gentoo Ebuild scripts for Krename."), "MvOstheim@web.de", "http://www.vonostheim.de"); aboutData.addCredit(i18n("Brandon Low"), i18n("Some GCC 3.1 fixes for Gentoo."), "lostlogic@gentoo.org", "http://www.gentoo.org"); aboutData.addCredit(i18n("Per Oyvind Karlsen"), i18n("Thanks for creating the Mandrake RPM"), "peroyvind@delonic.no"); aboutData.addCredit(i18n("Vincenzo Reale"), i18n("Italian translation"), "smart2128@baslug.org"); aboutData.addCredit(i18n("Daniele Medri"), i18n("Italian translation work"), "madrid@linuxmeeting.net"); aboutData.addCredit(i18n("Stephan Johach"), i18n("Provided a gcc3.x namespace patch"), "lucardus@onlinehome.de"); aboutData.addCredit(i18n("Michael Zugaro"), i18n("Provided the new preview and move features") , "michael.zugaro@college-de-france.fr"); aboutData.addCredit(i18n("Rene Gass"), i18n("Fixed problems with the spec file and contributed rpms for every SuSE version you can imagine and is also the new Gentoo maintainer for KRename"), "kde-package@gmx.de"); aboutData.addCredit(i18n("Mark Ziegler"), i18n("Provided SuSE RPMs and very good suggestions"), "mark.ziegler@rakekniven.de"); aboutData.addCredit(i18n("Jose Rodriguez"), i18n("Contributed a Spanish translation"), "chmpmi@eresmas.net"); aboutData.addCredit(i18n("Steven P. Ulrick"), i18n("Provided a RedHat RPM and was big help in improving KRename"), "steve@afolkey2.net"); aboutData.addCredit(i18n("UTUMI Hirosi"), i18n("Translated KRename to Japanese"), "utuhiro@mx12.freecom.ne.jp"); aboutData.addCredit(i18n("Nicolas Benoit"), i18n("Translated KRename into French"), "nbenoit@tuxfamily.org"); aboutData.addCredit(i18n("Krzysztof Pawlak"), i18n("Translated KRename into Polish"), "jmnemonic@gazeta.pl"); aboutData.addCredit(i18n("Ilya Ivkov"), i18n("Translated KRename into Russian"), "ilya-ivkov@yandex.ru"); aboutData.addCredit(i18n("Asim Husanovic"), i18n("Translated KRename into Bosnian"), "asim.h@megatel.ba"); aboutData.addCredit(i18n("Michal Smoczyk"), i18n("Polish Translation"), "msmoczyk@wp.pl"); aboutData.addCredit(i18n("Pavel Fric"), i18n("Czech Translation"), "pavelfric@seznam.cz"); aboutData.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); aboutData.setDesktopFileName(QStringLiteral("org.kde.krename")); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; parser.addPositionalArgument(QLatin1String("files"), i18n("Files to be added to the list to be renamed"), i18n("[files...]")); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("r"), i18n("add folder recursively"), i18n("folder"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("template"), i18n("set a template"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("extension"), i18n("set a template for the file extension"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("use-plugin"), i18n("enable a plugin for use"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("copy"), i18n("copy files to folder or url"), i18n("path or url"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("move"), i18n("move files to folder or url"), i18n("path or url"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("link"), i18n("link files to folder or url"), i18n("path or url"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("start"), i18n("start renaming immediately"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("test"), i18n("start KRename's selftest (developers only)"))); // This option was never implemented in the KDE4 version: //parser.addOption(QCommandLineOption(QStringList() << QLatin1String("previewitems"), i18n("only show preview items"), QLatin1String("num"))); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); app.setQuitOnLastWindowClosed(true); QWidget *krename = KRenameImpl::launch(QRect(0, 0, 0, 0), KRenameFile::List(), &parser); #ifndef Q_OS_WIN /* Check if Krename * was started from root! */ unsigned int uid = geteuid(); if (uid == 0) KMessageBox::information(krename, i18n( "Krename was started from root!
" "When started from root, Krename may damage your " "system if you do not know exactly what you are " "doing!" ), i18n("Error"), "KrenameRootWarning"); #endif // Q_OS_WIN /* * Activate this warning message for unstable development releases. */ /* KMessageBox::sorry( krename, i18n( "Warning ! This is a development release which may cause damage to your files!" "
Make backups before using KRename." )); */ return app.exec(); } diff --git a/src/permissionsplugin.cpp b/src/permissionsplugin.cpp index b3690bd..58b8996 100644 --- a/src/permissionsplugin.cpp +++ b/src/permissionsplugin.cpp @@ -1,377 +1,378 @@ /*************************************************************************** permissionsplugin.cpp - description ------------------- begin : Sun Mar 9 2008 copyright : (C) 2002 by Dominik Seichter email : domseichter@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ -#ifndef Q_OS_WIN #include "permissionsplugin.h" +#ifndef Q_OS_WIN + #include #include "ui_permissionspluginwidget.h" #include #include #include // OS includes #include #include #include #include #include #include // Only maxentries users are listed in the plugin // increase if you need more #define MAXENTRIES 1000 PermissionsPlugin::PermissionsPlugin(PluginLoader *loader) : QObject(nullptr), Plugin(loader), m_curPermission(S_IRUSR | S_IWUSR | S_IRGRP) { m_widget = new Ui::PermissionsPluginWidget(); int i; uid_t uid = getuid(); // Get all users on the system struct passwd *user; setpwent(); for (i = 0; ((user = getpwent()) != 0L) && (i < MAXENTRIES); ++i) { if (uid == 0 || uid == user->pw_uid) { m_users.append(QString::fromLatin1(user->pw_name)); } } endpwent(); // Get all groups on the system struct group *ge; user = getpwuid(uid); setgrent(); for (i = 0; ((ge = getgrent()) != 0L) && (i < MAXENTRIES); ++i) { if (uid == 0) { // Add all groups if we are run as root m_groups.append(QString::fromLatin1(ge->gr_name)); } else { // If the current user is member of this group: add it char **members = ge->gr_mem; char *member; while ((member = *members) != 0L) { if (strcmp(user->pw_name, member) == 0) { m_groups.append(QString::fromLatin1(ge->gr_name)); break; } ++members; } } } endgrent(); // add the users group ge = getgrgid(user->pw_gid); if (ge) { QString name = QString::fromLatin1(ge->gr_name); if (name.isEmpty()) { name.setNum(ge->gr_gid); } m_groups.append(name); } // sort both lists m_users.sort(); m_groups.sort(); } PermissionsPlugin::~PermissionsPlugin() { delete m_widget; } const QString PermissionsPlugin::name() const { return i18n("Permissions"); } const QPixmap PermissionsPlugin::icon() const { return KIconLoader::global()->loadIcon("document-properties", KIconLoader::NoGroup, KIconLoader::SizeSmall); } QString PermissionsPlugin::processFile(BatchRenamer *, int, const QString &filenameOrToken, EPluginType) { const QString &filename = filenameOrToken; if (!QUrl(filename).isLocalFile()) { return i18n("PermissionsPlugin works only with local files. %1 is a remote file.", filename); } if (m_widget->checkPermissions->isChecked()) { if (chmod(filename.toUtf8().data(), (mode_t)m_curPermission) == -1) { return i18n("Cannot chmod %1.", filename); } } if (m_widget->checkOwner->isChecked()) { uid_t uid = getUid(m_widget->comboUser->currentText()); gid_t gid = getGid(m_widget->comboGroup->currentText()); if (chown(filename.toUtf8().data(), uid, gid)) { return i18n("Cannot chown %1.", filename); } } return QString(); } void PermissionsPlugin::createUI(QWidget *parent) const { m_widget->setupUi(parent); m_widget->labelAdvanced->setVisible(false); m_widget->comboUser->insertItems(0, m_users); m_widget->comboGroup->insertItems(0, m_groups); m_widget->comboPermOwner->setCurrentIndex(2); m_widget->comboPermGroup->setCurrentIndex(1); m_widget->comboPermOthers->setCurrentIndex(0); connect(m_widget->checkOwner, &QCheckBox::clicked, this, &PermissionsPlugin::slotEnableControls); connect(m_widget->checkPermissions, &QCheckBox::clicked, this, &PermissionsPlugin::slotEnableControls); connect(m_widget->pushButton, &QPushButton::clicked, this, &PermissionsPlugin::slotAdvancedPermissions); connect(m_widget->comboPermOwner, static_cast(&QComboBox::activated), this, &PermissionsPlugin::slotUpdatePermissions); connect(m_widget->comboPermGroup, static_cast(&QComboBox::activated), this, &PermissionsPlugin::slotUpdatePermissions); connect(m_widget->comboPermOthers, static_cast(&QComboBox::activated), this, &PermissionsPlugin::slotUpdatePermissions); connect(m_widget->checkFolder, &QCheckBox::clicked, this, &PermissionsPlugin::slotUpdatePermissions); } void PermissionsPlugin::slotEnableControls() { m_widget->groupOwner->setEnabled(m_widget->checkOwner->isChecked()); m_widget->groupPermissions->setEnabled(m_widget->checkPermissions->isChecked()); } void PermissionsPlugin::slotAdvancedPermissions() { QDialog dialog; QLabel *la, *cl[3]; QGridLayout *gl; QCheckBox *permBox[3][4]; QVBoxLayout *layout = new QVBoxLayout(&dialog); QGroupBox *groupPermission = new QGroupBox(i18n("Access permissions"), &dialog); gl = new QGridLayout(groupPermission); //gl->addRowSpacing(0, 10); la = new QLabel(i18n("Class"), groupPermission); gl->addWidget(la, 1, 0); la = new QLabel(i18n("Read"), groupPermission); gl->addWidget(la, 1, 1); la = new QLabel(i18n("Write"), groupPermission); gl->addWidget(la, 1, 2); la = new QLabel(i18n("Exec"), groupPermission); QSize size = la->sizeHint(); size.setWidth(size.width() + 15); la->setFixedSize(size); gl->addWidget(la, 1, 3); la = new QLabel(i18n("Special"), groupPermission); gl->addWidget(la, 1, 4); cl[0] = new QLabel(i18n("User"), groupPermission); gl->addWidget(cl[0], 2, 0); cl[1] = new QLabel(i18n("Group"), groupPermission); gl->addWidget(cl[1], 3, 0); cl[2] = new QLabel(i18n("Others"), groupPermission); gl->addWidget(cl[2], 4, 0); la = new QLabel(i18n("UID"), groupPermission); gl->addWidget(la, 2, 5); la = new QLabel(i18n("GID"), groupPermission); gl->addWidget(la, 3, 5); la = new QLabel(i18n("Sticky"), groupPermission); gl->addWidget(la, 4, 5); int fperm[3][4] = { {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID}, {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID}, {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX} }; for (int row = 0; row < 3 ; ++row) { for (int col = 0; col < 4; ++col) { QCheckBox *cb = new QCheckBox(groupPermission); permBox[row][col] = cb; gl->addWidget(permBox[row][col], row + 2, col + 1); cb->setChecked(fperm[row][col] & m_curPermission); } } QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog); connect(box, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); connect(box, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); layout->addWidget(groupPermission); layout->addWidget(box); if (dialog.exec() == QDialog::Accepted) { m_curPermission = 0; for (int row = 0; row < 3; ++row) { for (int col = 0; col < 4; ++col) { if (permBox[row][col]->isChecked()) { m_curPermission |= fperm[row][col]; } } } //setCurrentPermissions( m_curPermission ); m_widget->labelAdvanced->setVisible(true); m_widget->comboPermOwner->setEnabled(false); m_widget->comboPermGroup->setEnabled(false); m_widget->comboPermOthers->setEnabled(false); m_widget->checkFolder->setEnabled(false); } } void PermissionsPlugin::slotUpdatePermissions() { int fpermUser [3] = { 0, S_IRUSR, S_IRUSR | S_IWUSR }; int fpermGroup[3] = { 0, S_IRGRP, S_IRGRP | S_IWGRP }; int fpermOther[3] = { 0, S_IROTH, S_IROTH | S_IWOTH }; m_curPermission = 0; m_curPermission |= (fpermUser[m_widget->comboPermOwner->currentIndex()]); m_curPermission |= (fpermGroup[m_widget->comboPermGroup->currentIndex()]); m_curPermission |= (fpermOther[m_widget->comboPermOthers->currentIndex()]); m_widget->checkFolder->setTristate(false); if (m_widget->checkFolder->isChecked()) { m_widget->checkFolder->setChecked(true); m_curPermission |= S_IXUSR; m_curPermission |= S_IXGRP; m_curPermission |= S_IXOTH; } } int PermissionsPlugin::getGid(const QString &group) const { int i, r = 0; struct group *ge; setgrent(); for (i = 0; ((ge = getgrent()) != 0L) && (i < MAXENTRIES); i++) if (!strcmp(ge->gr_name, group.toUtf8().data())) { r = ge->gr_gid; break; } endgrent(); return r; } int PermissionsPlugin::getUid(const QString &owner) const { int i, r = 0; struct passwd *user; setpwent(); for (i = 0; ((user = getpwent()) != 0L) && (i < MAXENTRIES); i++) if (!strcmp(user->pw_name, owner.toUtf8().data())) { r = user->pw_uid; break; } endpwent(); return r; } /* void PermissionsPlugin::setCurrentPermissions( int perm ) { m_widget->comboPermOwner->setCurrentIndex( 0 ); m_widget->comboPermGroup->setCurrentIndex( 0 ); m_widget->comboPermOthers->setCurrentIndex( 0 ); int fpermUser [3] = { 0, S_IRUSR, S_IRUSR | S_IWUSR }; int fpermGroup[3] = { 0, S_IRGRP, S_IRGRP | S_IWGRP }; int fpermOther[3] = { 0, S_IROTH, S_IROTH | S_IWOTH }; int i; for( i=2; i>=0; i-- ) { if( (fpermUser[i] & perm) ) { m_widget->comboPermOwner->setCurrentIndex( i ); break; } } for( i=2; i>=0; i-- ) { if( (fpermGroup[i] & perm) ) { m_widget->comboPermGroup->setCurrentIndex( i ); break; } } for( i=2; i>=0; i-- ) { if( (fpermOther[i] & perm) ) { m_widget->comboPermOthers->setCurrentIndex( i ); break; } } if( (perm & S_IXUSR) && (perm & S_IXGRP) && (perm & S_IXOTH) ) { m_widget->checkFolder->setTristate( false ); m_widget->checkFolder->setChecked( true ); } else { if( (perm & S_IXUSR) || (perm & S_IXGRP) || (perm & S_IXOTH) ) m_widget->checkFolder->setCheckState( Qt::PartiallyChecked ); } m_curPermission = perm; } */ #endif // Q_OS_WIN diff --git a/src/permissionsplugin.h b/src/permissionsplugin.h index a2c4fc9..e8928c2 100644 --- a/src/permissionsplugin.h +++ b/src/permissionsplugin.h @@ -1,164 +1,170 @@ /*************************************************************************** permissionsplugin.h - description ------------------- begin : Sun Mar 9 2008 copyright : (C) 2002 by Dominik Seichter email : domseichter@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef PERMISSIONS_PLUGIN_H #define PERMISSIONS_PLUGIN_H +#include + +#ifndef Q_OS_WIN + #include "plugin.h" #include namespace Ui { class PermissionsPluginWidget; }; /** This is the abstract interface that has to be implemented * by all KRename plugins. */ class PermissionsPlugin : public QObject, public Plugin { Q_OBJECT public: explicit PermissionsPlugin(PluginLoader *loader); virtual ~PermissionsPlugin(); /** * @returns a name of the plugin that can be displayed * to the user. This name should be internationalized. */ virtual const QString name() const; /** * Determines the type of the plugin. * Different enum values may be or'ed together. * * @returns the type of the plugin. */ inline virtual int type() const; /** * @returns an icon for this plugin. */ virtual const QPixmap icon() const; /** * @returns true if this plugins is always enabled * * Warning: If you return true here, the user has no possibility to * disable this plugin. */ inline virtual bool alwaysEnabled() const; /** * This function is the core of your plugin. * * It does the actual processing of a file, filename or token depending of the type * of your plugin. * * \see type() * * @param b the parent BatchRenamer instance calling this plugin * @param index the index of the current file (i.e. the first file has index 0, * the second file to be renamed has index 1 ....) * @param filenameOrToken this parameter depends on the type of your plugin. * If type is ePluginType_File, this is the absolute path * or URL to the renamed file. * If type is ePluginType_Filename, this is the filename * (without path) as created by KRename. * If type is ePluginType_Token, this is the contents of a token * in brackets. If your plugin supports the token [example], * KRename will pass the strign "example" to your method. * @param eCurrentType the current type of plugin that is requested (for plugins that support more than one type) * * @returns the result of the function, depending on type(). * @returns QString::null if this plugin has nothing to do. * @returns A new filename if type is ePluginType_Filename * @returns the value of the token if type is ePluginType_Token * @returns an error message or QString::null if type is ePluginType_File */ virtual QString processFile(BatchRenamer *b, int index, const QString &filenameOrToken, EPluginType eCurrentType); /** Get a list of all tokens supported by this plugin. * * If the token type != ePluginType_Token you have to return an empty list * * @returns a list of all supported tokens. The returned strings will be treated * as regular expressions to find a plugin which supports a token. */ inline virtual const QStringList &supportedTokens() const; /** Returns help descriptions for the supported tokens * * The returned stringlist contains strings that are the tokens * and the description separated by ;; * * @returns a stringlist containing help on the supported tokens */ inline virtual const QStringList &help() const; /** Create a user interface for this plugin * * @param parent the parent widget of this plugin */ virtual void createUI(QWidget *parent) const; private Q_SLOTS: void slotEnableControls(); void slotAdvancedPermissions(); void slotUpdatePermissions(); private: int getGid(const QString &group) const; int getUid(const QString &owner) const; //void setCurrentPermissions( int perm ); private: Ui::PermissionsPluginWidget *m_widget; int m_curPermission; ///< The current permissions QStringList m_tmp; ///< Dummy empty list so that we can return a reference for supported tokens and help QStringList m_users; ///< List of all usernames on the system QStringList m_groups; ///< List of all groups on the system }; inline int PermissionsPlugin::type() const { return ePluginType_File; } inline bool PermissionsPlugin::alwaysEnabled() const { return false; } inline const QStringList &PermissionsPlugin::supportedTokens() const { return m_tmp; } inline const QStringList &PermissionsPlugin::help() const { return m_tmp; } +#endif // Q_OS_WIN + #endif /* PERMISSIONS_PLUGIN_H */ diff --git a/src/pluginloader.cpp b/src/pluginloader.cpp index 0710e00..7932ba0 100644 --- a/src/pluginloader.cpp +++ b/src/pluginloader.cpp @@ -1,215 +1,217 @@ /*************************************************************************** pluginloader.cpp - description ------------------- begin : Sun Oct 7 2007 copyright : (C) 2007 by Dominik Seichter email : domseichter@web.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ +#include + #include "pluginloader.h" #include "krenameimpl.h" #include "plugin.h" #include "datetimeplugin.h" #include "dirsortplugin.h" #include "fileplugin.h" #include "increasecounterplugin.h" #include "permissionsplugin.h" #include "scriptplugin.h" #include "systemplugin.h" #include "translitplugin.h" #include "snumplugin.h" #include #include <../config-krename.h> #if HAVE_TAGLIB # include "taglibplugin.h" #endif // HAVE_TAGLIB #if HAVE_EXIV2 #include "exiv2plugin.h" #endif // HAVE_EXIV2 #if HAVE_PODOFO # include "podofoplugin.h" #endif // HAVE_PODOFO #if HAVE_FREETYPE # include "fontplugin.h" #endif // HAVE_FREETYPE PluginLoader *PluginLoader::s_instance = nullptr; PluginLoader *PluginLoader::Instance() { if (!s_instance) { s_instance = new PluginLoader(); } return s_instance; } PluginLoader::PluginLoader() { this->load(); } PluginLoader::~PluginLoader() { this->clear(); } Plugin *PluginLoader::findPlugin(const QString &token) { QString lower = token.toLower(); // first search in the cache Plugin *p = m_tokenCache[lower]; if (p) { return p; } // now search in all tokens QMap::const_iterator it = m_tokenMap.constBegin(); while (it != m_tokenMap.constEnd()) { if (QRegExp(it.key()).exactMatch(lower)) { // we found a plugin // put the token into the cache for quick access p = it.value(); m_tokenCache[lower] = p; return p; } ++it; } // add typos to the cache, too: // So that we find immediately that this key is not supported. m_tokenCache.insert(lower, nullptr); return nullptr; } Plugin *PluginLoader::findPluginByName(const QString &name) { QList::iterator it = m_plugins.begin(); while (it != m_plugins.end()) { if ((*it)->name() == name) { return *it; } ++it; } return nullptr; } void PluginLoader::clear() { QList::iterator it = m_plugins.begin(); while (it != m_plugins.end()) { delete *it; ++it; } m_plugins.clear(); m_tokenMap.clear(); m_tokenCache.clear(); } void PluginLoader::load() { #ifndef Q_OS_WIN m_plugins.append(new DateTimePlugin(this)); #endif m_plugins.append(new DirSortPlugin(this)); #if HAVE_EXIV2 m_plugins.append(new Exiv2Plugin(this)); #endif // HAVE_EXIV2 #if HAVE_FREETYPE m_plugins.append(new FontPlugin(this)); #endif // HAVE_FREETYPE m_plugins.append(new IncreaseCounterPlugin(this)); #ifndef Q_OS_WIN m_plugins.append(new PermissionsPlugin(this)); #endif m_plugins.append(new ScriptPlugin(this)); m_plugins.append(new SystemPlugin(this)); #if HAVE_TAGLIB m_plugins.append(new TagLibPlugin(this)); #endif // HAVE_TAGLIB #if HAVE_PODOFO m_plugins.append(new PodofoPlugin(this)); #endif // HAVE_PODOFO m_plugins.append(new TranslitPlugin(this)); m_plugins.append(new SnumPlugin(this)); //this->loadFilePlugins(); // Fill the token map QList::iterator it = m_plugins.begin(); while (it != m_plugins.end()) { if (((*it)->type() & ePluginType_Token)) { const QStringList &tokens = (*it)->supportedTokens(); QStringList::const_iterator itList = tokens.begin(); while (itList != tokens.end()) { m_tokenMap.insert((*itList).toLower(), *it); ++itList; } } ++it; } } void PluginLoader::registerForUpdates(KRenameImpl *krename) { m_observers.prepend(krename); } void PluginLoader::deregisterForUpdates(KRenameImpl *krename) { m_observers.removeOne(krename); } void PluginLoader::sendUpdatePreview() { QList::iterator it = m_observers.begin(); while (it != m_observers.end()) { (*it)->slotUpdatePreview(); ++it; } } void PluginLoader::loadConfig(KConfigGroup &group) { QList::const_iterator it = m_plugins.constBegin(); while (it != m_plugins.constEnd()) { (*it)->loadConfig(group); ++it; } } void PluginLoader::saveConfig(KConfigGroup &group) { QList::const_iterator it = m_plugins.constBegin(); while (it != m_plugins.constEnd()) { (*it)->saveConfig(group); ++it; } }