#include <iostream>
-#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); \
+ } \
+ } \
}
}
+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());
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(
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(
}
-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();
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();
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*)),
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;
}
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;
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)
}
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)
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) {
}
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) {
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)
}
}
if (it->isDir()) {
size += calculateFileSize(listDirFiles(it->absoluteFilePath()));
} else {
- size = ceil(static_cast<float>(it->size()) / 4096);
+ size = ceil(static_cast<float>(it->size()) / 524288);
}
res += size;
}
-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");
}
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();
}
+MoveThread::MoveThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {
+ barText = tr("moving %1");
+}
+
+
void MoveThread::run() {
mutex.lock();
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)
} 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;
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);
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);
void setBarSize(unsigned int size);
void updateProgress(int value);
- void updateFile(const QString &fileName);
+ void updateFile(const QString &name);
const QFileInfoList files;
QDir dest;
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&);
};
Q_OBJECT
public:
- explicit DeleteThread(const QFileInfoList &files) : FileManipulatorThread(files) {}
+ explicit DeleteThread(const QFileInfoList &files);
protected:
void run();
Q_OBJECT
public:
- explicit CopyThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {}
+ explicit CopyThread(const QFileInfoList &files, QDir &dest);
protected:
void run();
Q_OBJECT
public:
- explicit MoveThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {}
+ explicit MoveThread(const QFileInfoList &files, QDir &dest);
protected:
void run();