From 6e733888214ac8adfd79c1f2afc7b410a0302078 Mon Sep 17 00:00:00 2001 From: Lukas Hrazky Date: Sun, 18 Jul 2010 22:01:45 +0200 Subject: [PATCH] added filename and ETA information to progressbars Signed-off-by: Lukas Hrazky --- src/fileoperator.cpp | 245 +++++++++++++++++++++++++++++++++----------------- src/fileoperator.h | 35 +++++--- 2 files changed, 187 insertions(+), 93 deletions(-) diff --git a/src/fileoperator.cpp b/src/fileoperator.cpp index bbd3583..68ca019 100644 --- a/src/fileoperator.cpp +++ b/src/fileoperator.cpp @@ -28,54 +28,54 @@ #include -#define SHOW_ERROR_PROMPT(promptString) \ - response = FileOperator::NONE; \ - if (ignoreAll[errno]) { \ - response = FileOperator::IGNORE; \ - } else { \ - char buf[255]; \ - char *realBuf = strerror_r(errno, buf, 255); \ - emit showErrorPrompt(this, promptString + ". " + realBuf + ".", errno); \ - waitCond.wait(&mutex); \ +#define SHOW_ERROR_PROMPT(promptString, fileName) \ + response = FileOperator::NONE; \ + if (ignoreAll[errno]) { \ + response = FileOperator::IGNORE; \ + } else { \ + char buf[255]; \ + char *realBuf = strerror_r(errno, buf, 255); \ + emit showErrorPrompt(this, promptString + " " + realBuf + ".", fileName, errno); \ + waitCond.wait(&mutex); \ } -#define ERROR_PROMPT(operation, promptString) \ -{ \ - response = FileOperator::NONE; \ - while (!abort && operation) { \ - SHOW_ERROR_PROMPT(promptString) \ - if (response == FileOperator::IGNORE) { \ - break; \ - } \ - } \ +#define ERROR_PROMPT(operation, promptString, fileName) \ +{ \ + response = FileOperator::NONE; \ + while (!abort && operation) { \ + SHOW_ERROR_PROMPT(promptString, fileName) \ + if (response == FileOperator::IGNORE) { \ + break; \ + } \ + } \ } -#define ERROR_PROMPT_XP(operation, promptString, onIgnore, quitCmd) \ -{ \ - ERROR_PROMPT(operation, promptString) \ - if (abort || response == FileOperator::IGNORE) { \ - if (!abort) onIgnore; \ - quitCmd; \ - } \ +#define ERROR_PROMPT_XP(operation, promptString, fileName, onIgnore, quitCmd) \ +{ \ + ERROR_PROMPT(operation, promptString, fileName) \ + if (abort || response == FileOperator::IGNORE) { \ + if (!abort) onIgnore; \ + quitCmd; \ + } \ } -#define OVERWRITE_PROMPT(file, newFile) \ -{ \ - response = FileOperator::NONE; \ - \ - if (newFile.exists()) { \ - if (overwriteAll != FileOperator::NONE) { \ - response = overwriteAll; \ - } else { \ - bool dirOverDir = false; \ - if (newFile.isDir() && file.isDir()) dirOverDir = true; \ - emit showOverwritePrompt(this, newFile.absoluteFilePath(), dirOverDir); \ - waitCond.wait(&mutex); \ - } \ - } \ +#define OVERWRITE_PROMPT(file, newFile) \ +{ \ + response = FileOperator::NONE; \ + \ + if (newFile.exists()) { \ + if (overwriteAll != FileOperator::NONE) { \ + response = overwriteAll; \ + } else { \ + bool dirOverDir = false; \ + if (newFile.isDir() && file.isDir()) dirOverDir = true; \ + emit showOverwritePrompt(this, newFile.absoluteFilePath(), dirOverDir); \ + waitCond.wait(&mutex); \ + } \ + } \ } @@ -87,11 +87,23 @@ FileOperator::FileOperator(QWidget *parent) : QWidget(parent) { } +QString FileOperator::shortenPath(const QString &path) { + QString homePath = QFSFileEngine::homePath(); + QString result = path; + if (path.indexOf(homePath, 0) == 0) { + result.replace(0, homePath.size(), "~"); + } + + return result; +} + + void FileOperator::deleteFiles(const QFileInfoList &files) { QString title, desc; if (files.size() == 1) { title = tr("Delete file"); - desc = tr("Are you sure you want to delete %1?").arg(files[0].absoluteFilePath()); + desc = tr("Are you sure you want to delete %1?") + .arg(FileOperator::shortenPath(files[0].absoluteFilePath())); } else { title = tr("Delete files"); desc = tr("You are about to delete %1 files. Are you sure you want to continue?").arg(files.size()); @@ -115,12 +127,13 @@ void FileOperator::copyFiles(const QFileInfoList &files, QDir &destination) { QString title, desc; if (files.size() == 1) { title = tr("Copy file"); - desc = tr("Are you sure you want to copy %1 to %2?").arg(files[0].absoluteFilePath()) - .arg(destination.absolutePath()); + desc = tr("Are you sure you want to copy %1 to %2?") + .arg(FileOperator::shortenPath(files[0].absoluteFilePath())) + .arg(FileOperator::shortenPath(destination.absolutePath())); } else { title = tr("Copy files"); desc = tr("You are about to copy %1 files to %2. Are you sure you want to continue?") - .arg(files.size()).arg(destination.absolutePath()); + .arg(files.size()).arg(FileOperator::shortenPath(destination.absolutePath())); } int confirm = QMessageBox::warning( @@ -144,12 +157,13 @@ void FileOperator::moveFiles(const QFileInfoList &files, QDir &destination) { QString title, desc; if (files.size() == 1) { title = tr("Move file"); - desc = tr("Are you sure you want to move %1 to %2?").arg(files[0].absoluteFilePath()) - .arg(destination.absolutePath()); + desc = tr("Are you sure you want to move %1 to %2?") + .arg(FileOperator::shortenPath(files[0].absoluteFilePath())) + .arg(FileOperator::shortenPath(destination.absolutePath())); } else { title = tr("Move files"); desc = tr("You are about to move %1 files to %2. Are you sure you want to continue?") - .arg(files.size()).arg(destination.absolutePath()); + .arg(files.size()).arg(FileOperator::shortenPath(destination.absolutePath())); } int confirm = QMessageBox::warning( @@ -166,14 +180,18 @@ void FileOperator::moveFiles(const QFileInfoList &files, QDir &destination) { } -void FileOperator::showErrorPrompt(FileManipulatorThread* manipulator, const QString &message, const int err) { +void FileOperator::showErrorPrompt(FileManipulatorThread* manipulator, + const QString &message, + const QString &fileName, + const int err) +{ QMessageBox msgBox; msgBox.addButton(QMessageBox::Cancel); QAbstractButton *abortButton = msgBox.addButton(tr("Abort"), QMessageBox::DestructiveRole); QAbstractButton *retryButton = msgBox.addButton(QMessageBox::Retry); QAbstractButton *ignoreButton = msgBox.addButton(QMessageBox::Ignore); QAbstractButton *ignoreAllButton = msgBox.addButton(tr("Ignore All"), QMessageBox::AcceptRole); - msgBox.setText(message); + msgBox.setText(message.arg(FileOperator::shortenPath(fileName))); msgBox.exec(); @@ -204,10 +222,11 @@ void FileOperator::showOverwritePrompt( QAbstractButton *askButton = 0; if (dirOverDir) { - msgBox.setText(tr("Directory %1 already exists. Overwrite the files inside?").arg(fileName)); + msgBox.setText(tr("Directory %1 already exists. Overwrite the files inside?") + .arg(FileOperator::shortenPath(fileName))); askButton = msgBox.addButton(tr("Ask"), QMessageBox::AcceptRole); } else { - msgBox.setText(tr("File %1 already exists. Overwrite?").arg(fileName)); + msgBox.setText(tr("File %1 already exists. Overwrite?").arg(FileOperator::shortenPath(fileName))); } msgBox.exec(); @@ -229,31 +248,32 @@ void FileOperator::showOverwritePrompt( void FileOperator::remove(FileManipulatorThread* manipulator) { - layout()->removeWidget(manipulator->widget); + manipulator->wait(); + layout()->removeWidget(manipulator->progressBar); manipulatorList.removeAll(manipulator); delete manipulator; } void FileOperator::setBarSize(FileManipulatorThread* manipulator, unsigned int size) { - manipulator->widget->setMinimum(0); - manipulator->widget->setMaximum(size); + if (!manipulator->progressBar->maximum()) { + manipulator->startTime = time(0); + } + manipulator->progressBar->setMinimum(0); + manipulator->progressBar->setMaximum(size); } void FileOperator::updateProgress(FileManipulatorThread* manipulator, int value) { - if (manipulator->widget->value() + value > manipulator->widget->maximum()) { - std::cout << "WARNING, EXCEEDING MAXIMUM BY " << value << std::endl; - } - manipulator->widget->setValue(manipulator->widget->value() + value); + manipulator->setText(value); } void FileOperator::caterNewThread(FileManipulatorThread *thread) { manipulatorList.append(thread); - connect(thread, SIGNAL(showErrorPrompt(FileManipulatorThread*, const QString&, const int)), - this, SLOT(showErrorPrompt(FileManipulatorThread*, const QString&, const int))); + connect(thread, SIGNAL(showErrorPrompt(FileManipulatorThread*, const QString&, const QString&, const int)), + this, SLOT(showErrorPrompt(FileManipulatorThread*, const QString&, const QString&, const int))); connect(thread, SIGNAL(showOverwritePrompt(FileManipulatorThread*, const QString&, bool)), this, SLOT(showOverwritePrompt(FileManipulatorThread*, const QString&, bool))); connect(thread, SIGNAL(finished(FileManipulatorThread*)), @@ -263,27 +283,41 @@ void FileOperator::caterNewThread(FileManipulatorThread *thread) { connect(thread, SIGNAL(updateProgress(FileManipulatorThread*, int)), this, SLOT(updateProgress(FileManipulatorThread*, int))); - thread->widget->setValue(0); + thread->progressBar->setValue(0); - layout()->addWidget(thread->widget); - thread->start(); + layout()->addWidget(thread->progressBar); + thread->start(QThread::LowestPriority); } FileManipulatorThread::FileManipulatorThread(const QFileInfoList files, QDir dest) : - widget(new QProgressBar()), + progressBar(new QProgressBar()), + startTime(0), files(files), dest(dest), response(FileOperator::NONE), overwriteAll(FileOperator::NONE), abort(false), + lastTimeUpdate(0), barSize(0), barValue(0), fileSize(0), fileValue(0) { memset(ignoreAll, false, sizeof(ignoreAll)); - widget->setStyle(new QPlastiqueStyle); + progressBar->setMaximum(0); + QFont barFont = progressBar->font(); + barFont.setPointSize(12); + progressBar->setFont(barFont); + progressBar->setFormat(tr("Gathering information...")); + progressBar->setMinimumHeight(44); + progressBar->setStyle(new QPlastiqueStyle); + //progressBar->setStyle(new QMotifStyle); +} + + +FileManipulatorThread::~FileManipulatorThread() { + delete progressBar; } @@ -351,10 +385,10 @@ bool FileManipulatorThread::remove(const QFileInfo &file, const bool ignoreDirNo if (!remove(list, ignoreDirNotEmpty)) return false; ERROR_PROMPT(!engine.rmdir(path, false), - tr("Error deleting directory %1.").arg(path)) + tr("Error deleting directory %1."), path) } else { ERROR_PROMPT(!engine.remove(), - tr("Error deleting file %1.").arg(path)) + tr("Error deleting file %1."), path) } if (abort || response == FileOperator::IGNORE) return false; @@ -403,7 +437,7 @@ void FileManipulatorThread::copy(const QFileInfo &file, const bool removeAfterCo if (!newFile.exists()) { ERROR_PROMPT_XP(!engine.mkdir(newPath, false), - tr("Error creating directory %1.").arg(newPath), + tr("Error creating directory %1."), newPath, updateProgress(fileSizeMap[path]), break) } @@ -421,26 +455,26 @@ void FileManipulatorThread::copy(const QFileInfo &file, const bool removeAfterCo overwriteAll = tmpResp; ERROR_PROMPT(!newEngine.setPermissions(file.permissions()), - tr("Error setting permissions for directory %1.").arg(newPath)) + tr("Error setting permissions for directory %1."), newPath) if (abort) return; dest = destBackup; } else { ERROR_PROMPT_XP(engine.isSequential(), - tr("Cannot copy sequential file %1.").arg(path), + tr("Cannot copy sequential file %1."), path, updateProgress(fileSizeMap[path]), break) if (newFile.exists() && newFile.isDir()) { ERROR_PROMPT_XP(!remove(newPath), - tr("Cannot replace directory %1 due to previous errors.").arg(newPath), + tr("Cannot replace directory %1 due to previous errors."), newPath, updateProgress(fileSizeMap[path]), break) } ERROR_PROMPT_XP(!engine.open(QIODevice::ReadOnly), - tr("Error reading file %1.").arg(path), + tr("Error reading file %1."), path, updateProgress(fileSizeMap[path]), break) @@ -449,7 +483,7 @@ void FileManipulatorThread::copy(const QFileInfo &file, const bool removeAfterCo engine.seek(0); ERROR_PROMPT(!newEngine.open(QIODevice::WriteOnly | QIODevice::Truncate), - tr("Error writing file %1.").arg(newPath)) + tr("Error writing file %1."), newPath) if (abort || response == FileOperator::IGNORE) { if (response == FileOperator::IGNORE) { @@ -460,14 +494,14 @@ void FileManipulatorThread::copy(const QFileInfo &file, const bool removeAfterCo } bool error = false; - char block[4096]; + char block[524288]; qint64 bytes; while ((bytes = engine.read(block, sizeof(block))) > 0) { if (bytes == -1 || bytes != newEngine.write(block, bytes)) { if (bytes == -1) { - SHOW_ERROR_PROMPT(tr("Error while reading from file %1.").arg(path)); + SHOW_ERROR_PROMPT(tr("Error while reading from file %1."), path); } else { - SHOW_ERROR_PROMPT(tr("Error while writing to file %1.").arg(newPath)); + SHOW_ERROR_PROMPT(tr("Error while writing to file %1."), newPath); } if (!abort) { @@ -495,7 +529,7 @@ void FileManipulatorThread::copy(const QFileInfo &file, const bool removeAfterCo newEngine.remove(); } else { ERROR_PROMPT(!newEngine.setPermissions(file.permissions()), - tr("Error setting permissions for file %1.").arg(newPath)) + tr("Error setting permissions for file %1."), newPath) } } @@ -533,7 +567,7 @@ unsigned int FileManipulatorThread::calculateFileSize(const QFileInfoList &files if (it->isDir()) { size += calculateFileSize(listDirFiles(it->absoluteFilePath())); } else { - size = ceil(static_cast(it->size()) / 4096); + size = ceil(static_cast(it->size()) / 524288); } res += size; @@ -563,9 +597,42 @@ void FileManipulatorThread::updateProgress(int value) { } -void FileManipulatorThread::updateFile(const QString &fileName) { +void FileManipulatorThread::updateFile(const QString &name) { fileValue = 0; - emit updateFile(this, fileName); + fileName = FileOperator::shortenPath(name); + emit updateProgress(this, 0); +} + + +void FileManipulatorThread::setText(int value) { + if (progressBar->value() + value > progressBar->maximum()) { + std::cout << "WARNING, EXCEEDING MAXIMUM BY " << value << std::endl; + } + + time_t now = time(0); + if (lastTimeUpdate < now) { + lastTimeUpdate = now; + + time_t elapsed = now - startTime; + time_t remaining = (time_t) ((float) elapsed / barValue * (barSize - barValue)); + struct tm *ts = gmtime(&remaining); + + if (remaining < 60) { + strftime(timeBuf, sizeof(timeBuf), "%Ss", ts); + } else if (remaining < 3600) { + strftime(timeBuf, sizeof(timeBuf), "%M:%S", ts); + } else { + strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", ts); + } + } + + progressBar->setFormat(barText.arg(fileName) + "\n%p% ETA " + timeBuf); + progressBar->setValue(progressBar->value() + value); +} + + +DeleteThread::DeleteThread(const QFileInfoList &files) : FileManipulatorThread(files) { + barText = tr("deleting %1"); } @@ -587,22 +654,29 @@ void DeleteThread::perform(const QFileInfo &file) { QString path = file.absoluteFilePath(); QFSFileEngine engine(path); + updateFile(path); + if (file.isDir()) { processFiles(listDirFiles(path)); if (!listDirFiles(path).size()) { ERROR_PROMPT(!engine.rmdir(path, false), - tr("Error deleting directory %1.").arg(path)) + tr("Error deleting directory %1."), path) } } else { ERROR_PROMPT(!engine.remove(), - tr("Error deleting file %1.").arg(path)) + tr("Error deleting file %1."), path) } if (!abort) updateProgress(1); } +CopyThread::CopyThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) { + barText = tr("copying %1"); +} + + void CopyThread::run() { mutex.lock(); @@ -620,6 +694,11 @@ void CopyThread::perform(const QFileInfo &file) { } +MoveThread::MoveThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) { + barText = tr("moving %1"); +} + + void MoveThread::run() { mutex.lock(); @@ -678,7 +757,7 @@ void MoveThread::rename(const QFileInfoList &files, const QDir &dest) { overwriteAll = tmpResp; - ERROR_PROMPT(!engine.rmdir(path, false), tr("Error deleting directory %1.").arg(path)) + ERROR_PROMPT(!engine.rmdir(path, false), tr("Error deleting directory %1."), path) break; // source and target are nonmatching types(file and dir) @@ -686,7 +765,7 @@ void MoveThread::rename(const QFileInfoList &files, const QDir &dest) { } else if (errno == ENOTDIR || errno == EISDIR) { if (!remove(newPath)) break; } else { - SHOW_ERROR_PROMPT(tr("Error moving %1.").arg(path)) + SHOW_ERROR_PROMPT(tr("Error moving %1."), path) if (response == FileOperator::IGNORE) { break; diff --git a/src/fileoperator.h b/src/fileoperator.h index 7672de1..9e2dcfb 100644 --- a/src/fileoperator.h +++ b/src/fileoperator.h @@ -40,13 +40,21 @@ public: FileOperator(QWidget *parent = 0); + static QString shortenPath(const QString &path); + void deleteFiles(const QFileInfoList &files); void copyFiles(const QFileInfoList &files, QDir &destination); void moveFiles(const QFileInfoList &files, QDir &destination); public slots: - void showErrorPrompt(FileManipulatorThread* manipulator, const QString &message, const int err); - void showOverwritePrompt(FileManipulatorThread* manipulator, const QString &fileName, const bool dirOverDir); + void showErrorPrompt(FileManipulatorThread* manipulator, + const QString &message, + const QString &fileName, + const int err); + void showOverwritePrompt(FileManipulatorThread* manipulator, + const QString &fileName, + const bool dirOverDir); + void remove(FileManipulatorThread* manipulator); void setBarSize(FileManipulatorThread* manipulator, unsigned int size); void updateProgress(FileManipulatorThread* manipulator, int value); @@ -63,15 +71,20 @@ class FileManipulatorThread : public QThread { public: explicit FileManipulatorThread(const QFileInfoList files, QDir dest = QDir()); + ~FileManipulatorThread(); void setResponse(const FileOperator::Response response, const bool appyToAll = false, const int err = 0); - QProgressBar *widget; + void setText(int value); + + QProgressBar *progressBar; + + time_t startTime; protected: void processFiles(const QFileInfoList &files); virtual void perform(const QFileInfo &file) = 0; - bool remove(QString &filename, const bool ignoreDirNotEmpty = false); + bool remove(QString &fileName, const bool ignoreDirNotEmpty = false); bool remove(const QFileInfoList &files, const bool ignoreDirNotEmpty = false); bool remove(const QFileInfo &file, const bool ignoreDirNotEmpty = false); @@ -84,7 +97,7 @@ protected: void setBarSize(unsigned int size); void updateProgress(int value); - void updateFile(const QString &fileName); + void updateFile(const QString &name); const QFileInfoList files; QDir dest; @@ -99,15 +112,17 @@ protected: QMutex mutex; QWaitCondition waitCond; + QString fileName, barText; + time_t lastTimeUpdate; + char timeBuf[10]; unsigned int barSize, barValue, fileSize, fileValue; signals: - void showErrorPrompt(FileManipulatorThread*, const QString&, const int); + void showErrorPrompt(FileManipulatorThread*, const QString&, const QString&, const int); void showOverwritePrompt(FileManipulatorThread*, const QString&, const bool); void finished(FileManipulatorThread*); void setBarSize(FileManipulatorThread*, unsigned int); void updateProgress(FileManipulatorThread*, int); - void updateFile(FileManipulatorThread*, const QString&); }; @@ -115,7 +130,7 @@ class DeleteThread : public FileManipulatorThread { Q_OBJECT public: - explicit DeleteThread(const QFileInfoList &files) : FileManipulatorThread(files) {} + explicit DeleteThread(const QFileInfoList &files); protected: void run(); @@ -127,7 +142,7 @@ class CopyThread : public FileManipulatorThread { Q_OBJECT public: - explicit CopyThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {} + explicit CopyThread(const QFileInfoList &files, QDir &dest); protected: void run(); @@ -139,7 +154,7 @@ class MoveThread : public FileManipulatorThread { Q_OBJECT public: - explicit MoveThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {} + explicit MoveThread(const QFileInfoList &files, QDir &dest); protected: void run(); -- 1.7.9.5