}
if (ignore)
continue;
- if (m_stop)
+ if (m_stop)
break;
if (depth >= m_minDepth && isValid(*it)){
bool isDir = it->isDir();
*/
void FileFinder::search(){
clock_t start = clock();
- setStop(false);
+ setStop(false);
m_statistics.clear();
QString path = ReFileUtils::nativePath(m_baseDir);
- path = ReQStringUtils::chomp(path, OS_SEPARATOR);
+ ReQStringUtils::chomp(path, OS_SEPARATOR);
fillTable(path, 0);
m_statistics.m_runtimeSeconds = (double) (clock() - start)
/ CLOCKS_PER_SEC;
*/
void FileFinder::setStop(bool stop)
{
- m_stop = stop;
+ m_stop = stop;
}
* @throws ConverterException
*/
bool Converter::error(const QString& message){
- m_mainWindow->log(message);
+ m_mainWindow->externalError(message);
throw ConverterException(message);
return false;
}
* @return <code>true</code>
*/
bool Converter::log(const QString& message){
- printf("%s\n", I18N::s2b(message).constData());
- m_mainWindow->log(message);
+ //printf("%s\n", I18N::s2b(message).constData());
+ m_mainWindow->externalLog(message);
return true;
}
*
* @param source the file's name with path
* @param target the new filename with path
+ * @param no the current number of the image file
* @param size the size of the file (in byte)
- * @param sizeTarget OUT: the file size of the target
+ * @param preSize IN/OUT: the sum of the file sizes before converting
+ * @param postSize IN/OUT: the sum of the file sizes after converting
*/
void TaskConverter::convertOneFile(const QString& source, const QString& target,
- qint64 size, qint64& sizeTarget){
+ int no, qint64 size, qint64& preSize, qint64& postSize){
int width = 0;
int height = 0;
QString info;
else
handleUserDefined(width, height, widthNew, heightNew);
QString relPath = source.mid(m_sourceDir.length());
- log(
- relPath + " " + ReQStringUtils::readableSize(size)
- + QString(" -> %1x%2 ").arg(widthNew).arg(heightNew));
+ QString message = relPath + " " + ReQStringUtils::readableSize(size)
+ + " " + info;
callExternalProgram(source, target, width, height, widthNew, heightNew, m_quality);
- struct stat info;
- if (stat(I18N::s2b(target).constData(), &info) == 0){
- sizeTarget = info.st_size;
- m_mainWindow->externalAppend(ReGuiQueueItem::ListAppendToCurrent,
- NULL, ReQStringUtils::readableSize(sizeTarget)
- + " " + ReQStringUtils::readableDuration(
- clock() - start));
+ struct stat fileInfo;
+ if (stat(I18N::s2b(target).constData(), &fileInfo) != 0){
+ error(tr("target file was not created: ") + relPath);
+ } else if (fileInfo.st_size == 0){
+ error (tr("target file was empty: ") + relPath);
+ } else if (! readProperties(target, widthNew, heightNew, info)){
+ error(tr("cannot read image properties from ") + target);
+ } else {
+ preSize += size;
+ postSize += fileInfo.st_size;
+ message += "-> " + info + " " + ReQStringUtils::readableSize(fileInfo.st_size)
+ + " " + ReQStringUtils::readableDuration(clock() - start);
+ log(message);
+ int percentFiles = int(no * 100 / max(1, m_totalFiles));
+ int percentSize = int(preSize * 100 / max(1, min(preSize, m_totalBytes)));
+ int percent = preSize > m_totalBytes ? percentFiles
+ : (2 * percentFiles + percentSize) / 3;
+ info = tr("%1 file(s) of %2 (%3 %), %4 -> %5 (%6 %)")
+ .arg(no).arg(m_totalFiles)
+ .arg(percent)
+ .arg(ReQStringUtils::readableSize(preSize))
+ .arg(ReQStringUtils::readableSize(postSize))
+ .arg(postSize * 100.0 / max(1LL, preSize), 0,
+ 'f', 1);
+ m_mainWindow->externalAppend(ReGuiQueueItem::StatusLine, NULL, info);
}
}
}
clock_t start = clock();
qint64 preSize = 0;
qint64 postSize = 0;
- qint64 lengthTarget = 0;
int no = 0;
QString info;
QString node;
int ix = info.indexOf('\t');
node = info.mid(ix + 1);
info.resize(ix);
- targetDir = m_targetDir;
- if (!info.isEmpty())
- targetDir += info + OS_SEPARATOR;
+ targetDir = m_targetDir + info;
+ ReQStringUtils::chomp(targetDir, OS_SEPARATOR);
if (! QDir(targetDir).exists())
- _mkdir(I18N::s2b(targetDir).constData());
+ ReFileUtils::makeDirWithParents(targetDir, m_mainWindow->logger());
QDir dir(targetDir);
if (! dir.exists()){
error(tr("cannot create directory: %1").arg(targetDir));
QString nodeTarget = ReFileUtils::replaceExtension(node,
"." + m_targetType);
QString target = m_targetDir + info + nodeTarget;
- convertOneFile(path, target, length, lengthTarget);
- preSize += length;
- postSize += lengthTarget;
- int percentFiles = int(no * 100 / max(1, m_totalFiles));
- int percentSize = int(preSize * 100 / max(1, min(preSize, m_totalBytes)));
- int percent = preSize > m_totalBytes ? percentFiles
- : (2 * percentFiles + percentSize) / 3;
- info = tr("%1 file(s) of %2 (%3 %), %4 -> %5 (%6 %)")
- .arg(no).arg(m_totalFiles)
- .arg(percent)
- .arg(ReQStringUtils::readableSize(preSize))
- .arg(ReQStringUtils::readableSize(postSize))
- .arg(postSize * 100.0 / max(1LL, preSize), 0,
- 'f', 1);
- m_mainWindow->externalStatusMessage(LOG_INFO, info);
+ convertOneFile(path, target, no, length, preSize, postSize);
}
}
int height, int widthNew, int heightNew, int quality);
void converterTask();
void convertOneFile(const QString& source, const QString& target,
- qint64 size, qint64& sizeTarget);
+ int no, qint64 size, qint64& preSize, qint64& postSize);
bool handleSimple(int width, int height, int& widthNew, int& heightNew);
bool handleUserDefined(int width, int height, int& widthNew, int& heightNew);
bool readProperties(const QString& name, int &width, int &height,
case ReGuiQueueItem::LogMessage:
say(LOG_INFO, item.m_value);
break;
+ case ReGuiQueueItem::LogError:
+ error(item.m_value);
+ break;
case ReGuiQueueItem::StatusLine:
- externalStatusMessage(false, item.m_value);
+ setStatusMessage(false, item.m_value);
break;
case ReGuiQueueItem::ListAppendToCurrent:
{
* @param error <code>true</code>: the message is an error message
* @param message the text to set
*/
-void MainWindow::externalStatusMessage(bool error, const QString& message){
+void MainWindow::setStatusMessage(bool error, const QString& message){
RE_UNUSED(error);
m_statusMessage->setText(message);
}
virtual void aboutToQuit();
bool error(const QString& message);
bool log(const QString& message);
- void externalStatusMessage(bool error, const QString& message);
+ void setStatusMessage(bool error, const QString& message);
public:
virtual bool say(ReLoggerLevel level, const QString& message);
private:
LOC_DELETE_TREE_2, // 11802
LOC_DELETE_TREE_3, // 11803
LOC_SET_TIMES_1, // 11804
+ LOC_MAKE_DIR_1, // 11805
+ LOC_MAKE_DIR_2, // 11806
};
QDateTime ReFileUtils::m_undefinedTime;
m_fileSizes(0L) {
}
-/**
- * Appends a relative path to base directory name (absolute or relative).
+
+/** Normalizes a file path.
*
- * @param base the base directory, relative or absolute
- * @param path a relative path (relative to <code>base</code>)
- * @return <code>path</code> if it is an absolute path<br>
- * otherwise: the combined path
+ * Removes duplicated slashes and "." and "..", but not leading "..".
+ * Change the 2nd separator to the native separator, e.g. "/" to "\\"
+ *
+ * @param path path to clean
+ * @return the path without duplicated separators and "." and ".."
*/
-QString ReFileUtils::pathAppend(const QString& base, const QString& path) {
- QString rc;
- if (isAbsolutPath(path))
- rc = path;
- else if (!base.isEmpty())
- rc = QDir::cleanPath(base + OS_SEPARATOR + path);
- else {
- rc = path;
- rc.replace("\\", "/");
- if (path.startsWith("/"))
- rc.remove(0, 1);
+QByteArray ReFileUtils::cleanPath(const char* path) {
+ QByteArray rc;
+ int length = strlen(path);
+ rc.reserve(length);
+ int minLength = 0;
+#ifdef __WIN32__
+ // UNC path, e.g. "\\server\share"?
+ if ((path[0] == OS_SEPARATOR || path[0] == OS_2nd_SEPARATOR)
+ && (path[1] == OS_SEPARATOR || path[1] == OS_2nd_SEPARATOR)) {
+ rc.append("\\\\");
+ path += 2;
+ minLength = 2;
+ }
+#endif
+ char cc = *path;
+ int startNode = 0;
+ if (cc == OS_SEPARATOR || cc == OS_2nd_SEPARATOR){
+ path++;
+ startNode++;
+ rc.append(OS_SEPARATOR);
+ }
+ while ((cc = *path++) != '\0') {
+ if (cc != OS_SEPARATOR && cc != OS_2nd_SEPARATOR)
+ rc.append(cc);
+ // ignore duplicated slashes:
+ else if (rc.length() > 0 && rc.at(rc.length() - 1) != OS_SEPARATOR){
+ int length = rc.length() - startNode;
+ if (length == 1 && rc.at(startNode) == '.') {
+ // ignore ".": remove it:
+ rc.resize(startNode);
+ } else if (length == 2 && rc.at(startNode) == '.' &&rc.at(startNode + 1) == '.') {
+ // remove "..":
+ rc.resize(startNode);
+ // remove the last slash and node
+ if (rc.length() > minLength) {
+ rc.resize(rc.size() - 1);
+ int ix = rc.lastIndexOf(OS_SEPARATOR);
+ if (ix > minLength)
+ rc.resize(ix + 1);
+ startNode = rc.length();
+ }
+ } else {
+ rc.append(OS_SEPARATOR);
+ startNode = rc.length();
+ }
+ }
+ }
+ length = rc.length() - startNode;
+ if (length == 1 && rc.at(startNode) == '.') {
+ // ignore ".": remove it:
+ rc.resize(startNode);
+ } else if (length == 2 && rc.at(startNode) == '.'
+ && startNode > 0 &&rc.at(startNode + 1) == '.') {
+ // remove "..":
+ rc.resize(startNode);
+ // remove the last slash and node
+ if (rc.length() > minLength) {
+ rc.resize(rc.size() - 1);
+ int ix = rc.lastIndexOf(OS_SEPARATOR);
+ if (ix > minLength)
+ rc.resize(ix);
+ }
}
return rc;
}
-/**
- * Appends a relative path to base directory name (absolute or relative).
+/** Normalizes a file path.
*
- * @param base the base directory, relative or absolute
- * @param path a relative path (relative to <code>base</code>)
- * @return <code>path</code> if it is an absolute path<br>
- * otherwise: the combined path
+ * Removes duplicated slashes and "." and "..", but not leading "..".
+ * Change the 2nd separator to the native separator, e.g. "/" to "\\"
+ *
+ * @param path path to clean
+ * @return the path without duplicated separators and "." and ".."
*/
-QByteArray ReFileUtils::pathAppend(const char* base, const char* path) {
- QByteArray rc;
- if (base[0] != '\0') {
- rc.append(base).append(OS_SEPARATOR).append(path);
- } else {
- rc = path;
- }
- return cleanPath(rc.constData());
+QString ReFileUtils::cleanPath(const QString& path) {
+ return (QString) cleanPath(I18N::s2b(path).constData());
}
/**
#endif
}
+/**
+ * Creates a directory (if not it does not exist) and logs errors.
+ *
+ * @param path the full name
+ * @param logger NULL or the logger
+ * @return <code>true</code>: success: the directory exists<br>
+ * <code>false</code>: error occurred
+ */
+bool ReFileUtils::makeDir(const char* path, ReLogger* logger) {
+ struct stat info;
+ bool rc = true;
+ if (stat(path, &info) != 0) {
+ rc = _mkdir(path) == 0;
+ if (!rc && logger != NULL)
+ logger->log(LOG_ERROR, LOC_MAKE_DIR_1,
+ QObject::tr("can't create directory (%1): %2").arg(errno).arg(path));
+ } else if (!S_ISDIR(info.st_mode)) {
+ rc = false;
+ if (logger != NULL)
+ logger->log(LOG_ERROR, LOC_MAKE_DIR_2,
+ QObject::tr("can't create directory (is a file): ") + path);
+ }
+ return rc;
+}
+/**
+ * Creates a directory (if not it does not exist) and logs errors.
+ *
+ * @param path the full name
+ * @param logger NULL or the logger
+ * @return <code>true</code>: success: the directory exists<br>
+ * <code>false</code>: error occurred
+ */
+bool ReFileUtils::makeDir(const QString& path, ReLogger* logger) {
+ return makeDir(I18N::s2b(path).constData(), logger);
+}
+/**
+ * Creates a directory and (if necessary) its parent directories.
+ *
+ * @param path the full name
+ * @param logger NULL or the logger
+ * @return <code>true</code>: success: the directory exists<br>
+ * <code>false</code>: error occurred
+ */
+bool ReFileUtils::makeDirWithParents(const char* path, ReLogger* logger) {
+ const char* end;
+ const char* start = path;
+ bool rc = true;
+ QByteArray dir;
+ while (rc && (end = strchr(start, OS_SEPARATOR)) != NULL) {
+ if (end == path) {
+ start++;
+ dir += OS_SEPARATOR;
+ } else {
+ dir.append(start, end - start);
+ start = end + 1;
+ rc = makeDir(dir.constData(), logger);
+ dir += OS_SEPARATOR;
+ }
+ }
+ if (rc && start[0] != '\0') {
+ dir.append(start);
+ rc = makeDir(dir.constData(), logger);
+ }
+ return rc;
+}
+
+/**
+ * Creates a directory and (if necessary) its parent directories.
+ *
+ * @param path the full name
+ * @param logger NULL or the logger
+ * @return <code>true</code>: success: the directory exists<br>
+ * <code>false</code>: error occurred
+ */
+bool ReFileUtils::makeDirWithParents(const QString& path, ReLogger* logger) {
+ return makeDirWithParents(I18N::s2b(path).constData(), logger);
+}
+
/**
* Extracts the node of a filename.
*
return rc;
}
-/** Normalizes a file path.
- *
- * Removes duplicated slashes and "." and "..", but not leading "..".
- * Change the 2nd separator to the native separator, e.g. "/" to "\\"
+/**
+ * Appends a relative path to base directory name (absolute or relative).
*
- * @param path path to clean
- * @return the path without duplicated separators and "." and ".."
+ * @param base the base directory, relative or absolute
+ * @param path a relative path (relative to <code>base</code>)
+ * @return <code>path</code> if it is an absolute path<br>
+ * otherwise: the combined path
*/
-QByteArray ReFileUtils::cleanPath(const char* path) {
- QByteArray rc;
- int length = strlen(path);
- rc.reserve(length);
- int minLength = 0;
-#ifdef __WIN32__
- // UNC path, e.g. "\\server\share"?
- if ((path[0] == OS_SEPARATOR || path[0] == OS_2nd_SEPARATOR)
- && (path[1] == OS_SEPARATOR || path[1] == OS_2nd_SEPARATOR)) {
- rc.append("\\\\");
- path += 2;
- minLength = 2;
- }
-#endif
- char cc = *path;
- int startNode = 0;
- if (cc == OS_SEPARATOR || cc == OS_2nd_SEPARATOR){
- path++;
- startNode++;
- rc.append(OS_SEPARATOR);
- }
- while ((cc = *path++) != '\0') {
- if (cc != OS_SEPARATOR && cc != OS_2nd_SEPARATOR)
- rc.append(cc);
- // ignore duplicated slashes:
- else if (rc.length() > 0 && rc.at(rc.length() - 1) != OS_SEPARATOR){
- int length = rc.length() - startNode;
- if (length == 1 && rc.at(startNode) == '.') {
- // ignore ".": remove it:
- rc.resize(startNode);
- } else if (length == 2 && rc.at(startNode) == '.' &&rc.at(startNode + 1) == '.') {
- // remove "..":
- rc.resize(startNode);
- // remove the last slash and node
- if (rc.length() > minLength) {
- rc.resize(rc.size() - 1);
- int ix = rc.lastIndexOf(OS_SEPARATOR);
- if (ix > minLength)
- rc.resize(ix + 1);
- startNode = rc.length();
- }
- } else {
- rc.append(OS_SEPARATOR);
- startNode = rc.length();
- }
- }
- }
- length = rc.length() - startNode;
- if (length == 1 && rc.at(startNode) == '.') {
- // ignore ".": remove it:
- rc.resize(startNode);
- } else if (length == 2 && rc.at(startNode) == '.'
- && startNode > 0 &&rc.at(startNode + 1) == '.') {
- // remove "..":
- rc.resize(startNode);
- // remove the last slash and node
- if (rc.length() > minLength) {
- rc.resize(rc.size() - 1);
- int ix = rc.lastIndexOf(OS_SEPARATOR);
- if (ix > minLength)
- rc.resize(ix);
- }
+QString ReFileUtils::pathAppend(const QString& base, const QString& path) {
+ QString rc;
+ if (isAbsolutPath(path))
+ rc = path;
+ else if (!base.isEmpty())
+ rc = QDir::cleanPath(base + OS_SEPARATOR + path);
+ else {
+ rc = path;
+ rc.replace("\\", "/");
+ if (path.startsWith("/"))
+ rc.remove(0, 1);
}
return rc;
}
-/** Normalizes a file path.
- *
- * Removes duplicated slashes and "." and "..", but not leading "..".
- * Change the 2nd separator to the native separator, e.g. "/" to "\\"
+/**
+ * Appends a relative path to base directory name (absolute or relative).
*
- * @param path path to clean
- * @return the path without duplicated separators and "." and ".."
+ * @param base the base directory, relative or absolute
+ * @param path a relative path (relative to <code>base</code>)
+ * @return <code>path</code> if it is an absolute path<br>
+ * otherwise: the combined path
*/
-QString ReFileUtils::cleanPath(const QString& path) {
- return (QString) cleanPath(I18N::s2b(path).constData());
+QByteArray ReFileUtils::pathAppend(const char* base, const char* path) {
+ QByteArray rc;
+ if (base[0] != '\0') {
+ rc.append(base).append(OS_SEPARATOR).append(path);
+ } else {
+ rc = path;
+ }
+ return cleanPath(rc.constData());
}
/**
return path.replace(OS_2nd_SEPARATOR, OS_SEPARATOR);
#endif
}
+ static bool makeDir(const char* path, ReLogger* logger);
+ static bool makeDir(const QString& path, ReLogger* logger);
+ static bool makeDirWithParents(const char* path, ReLogger* logger);
+ static bool makeDirWithParents(const QString& path, ReLogger* logger);
static QString nodeOf(const QString& filename);
static QByteArray nodeOf(const char* filename);
static QString parentOf(const QString& filename);
/**
* Removes end of line characters if any.
*
- * @param text text to inspect
+ * @param text IN: text to inspect<br>
+ * OUT: without trailing <code>cc</code>
* @param cc character to remove. If '\\n' also '\\r' will be removed
- * @return <code>text</code> without trailing <code>cc</code>
+ * @return <code>text</code>
*/
-ReString ReQStringUtils::chomp(const ReString& text, char cc) {
+ReString& ReQStringUtils::chomp(ReString& text, char cc) {
int last = text.length() - 1;
- if (last < 0)
- return text;
- else {
+ if (last >= 0){
if (cc != '\n'){
- return text.at(last) == cc ? text.mid(0, last) : text;
+ text.resize(last);
} else {
while (last >= 0 && (text[last] == '\n' || text[last] == '\r')) {
last--;
}
- return last == text.length() - 1 ? text : text.left(last + 1);
+ text.resize(last);
}
}
+ return text;
}
/**
*/
class ReQStringUtils {
public:
- static ReString chomp(const ReString& text, char cc = '\n');
+ static ReString& chomp(ReString& text, char cc = '\n');
static int countOf(const QString& value, QChar toFind, int start = 0);
static QString& ensureLastChar(QString& value, QChar lastChar);
static int lengthOfDate(const ReString& text, int start = 0, QDate* value =
/**
* Removes a given character from the end of the string if it is there.
*
- * @param string string to change
+ * @param string IN: string to inspect
+ * OUT: string without trailing <code>cc</code>
* @param cc character to remove. Default: end of line ('\n')<br>
* If <code>cc</code> is '\n' then also '\\r' will be removed
* at the end of the string
#define OS_2nd_SEPARATOR '\\'
#define OS_2nd_SEPARATOR_STR "\\"
#define _memicmp memicmp
-#define _mkdir(path) mkdir(path, -1)
+#define _mkdir(path) mkdir(path, ALLPERMS)
#define _rmdir rmdir
#define _unlink unlink
typedef qint64 uint64_t;
m_guiTimer->start(100);
}
+/**
+ * Returns the logger.
+ *
+ * @return the logger
+ */
+ReLogger* ReGuiApplication::logger()
+{
+ return &m_logger;
+}
+
/**
* @brief Logs a message
*
}
+/**
+ * Writes a text to the log.
+ *
+ * Note: this method is called from a non-main thread
+ *
+ * @param message the text to set
+ */
+void ReGuiApplication::externalError(const QString& message){
+ m_mutexGuiQueue.lock();
+ m_guiQueue.pushBack(ReGuiQueueItem(ReGuiQueueItem::LogError, NULL,
+ message));
+ m_mutexGuiQueue.unlock();
+}
+
/**
* Writes a text to the log.
*
public:
static QString buildHomeDir(QString homeDirBase, const QString& node);
bool externalAppend(ReGuiQueueItem::WidgetType type, QWidget* widget, const QString& info);
+ void externalError(const QString& message);
void externalLog(const QString& message);
void externalTaskFinished(const QString& message);
+ ReLogger* logger();
+
protected:
void initializeGuiElements();
protected slots: