#include <QHBoxLayout>
#include <QChar>
+#include "dialog.h"
+
#include <math.h>
#include <errno.h>
#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 ERROR_PROMPT(operation, promptString) \
-{ \
- response = FileOperator::NONE; \
- while (!abort && operation) { \
- SHOW_ERROR_PROMPT(promptString) \
- if (response == FileOperator::IGNORE) { \
- break; \
- } \
- } \
-}
+#define BLOCK_SIZE 524288
-#define ERROR_PROMPT_XP(operation, promptString, onIgnore, quitCmd) \
-{ \
- ERROR_PROMPT(operation, promptString) \
- if (abort || response == FileOperator::IGNORE) { \
- if (!abort) onIgnore; \
- quitCmd; \
- } \
-}
+#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 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 ERROR_PROMPT(operation, promptString, fileName) \
+{ \
+ response = FileOperator::NONE; \
+ while (!abort && operation) { \
+ SHOW_ERROR_PROMPT(promptString, fileName) \
+ if (response == FileOperator::IGNORE) { \
+ break; \
+ } \
+ } \
+}
+
+
+#define SPECIAL_COPY_ERROR_PROMPT(operation, promptString, fileName) \
+{ \
+ ERROR_PROMPT(operation, promptString, fileName) \
+ if (abort || response == FileOperator::IGNORE) { \
+ if (!abort) { \
+ updateProgress(fileSizeMap[path]); \
+ removeExcludeFiles.insert(path); \
+ } \
+ return; \
+ } \
+}
+
+
+#define OVERWRITE_PROMPT(file, newFile) \
+{ \
+ response = FileOperator::NONE; \
+ \
+ while (response == FileOperator::NONE && newFile.exists()) { \
+ if (overwriteAll != FileOperator::NONE) { \
+ response = overwriteAll; \
+ } else { \
+ emit showOverwritePrompt(this, newFile.absoluteFilePath(), \
+ newFile.isDir() && file.isDir()); \
+ waitCond.wait(&mutex); \
+ \
+ if (response == FileOperator::NONE) { \
+ emit showInputFilenamePrompt(this, newFile, file.isDir()); \
+ waitCond.wait(&mutex); \
+ if (newNameFromDialog.size()) { \
+ newFile.setFile(newNameFromDialog); \
+ } \
+ } \
+ } \
+ } \
+ if (response == FileOperator::ASK) response = FileOperator::NONE; \
}
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
setLayout(layout);
+ qRegisterMetaType<QFileInfo>("QFileInfo");
+}
+
+
+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;
}
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();
const QString &fileName,
const bool dirOverDir)
{
- QMessageBox msgBox;
- msgBox.addButton(QMessageBox::Cancel);
- QAbstractButton *yesButton = msgBox.addButton(QMessageBox::Yes);
- QAbstractButton *yesToAllButton = msgBox.addButton(QMessageBox::YesToAll);
- QAbstractButton *noButton = msgBox.addButton(QMessageBox::No);
- QAbstractButton *noToAllButton = msgBox.addButton(QMessageBox::NoToAll);
- QAbstractButton *abortButton = msgBox.addButton(tr("Abort"), QMessageBox::DestructiveRole);
+ Dialog msgBox;
+ msgBox.addButtonFirst(QDialogButtonBox::Cancel);
+ QAbstractButton *yesButton = msgBox.addButtonFirst(QDialogButtonBox::Yes);
+ QAbstractButton *yesToAllButton = msgBox.addButtonFirst(QDialogButtonBox::YesToAll);
+ QAbstractButton *noButton = msgBox.addButtonSecond(QDialogButtonBox::No);
+ QAbstractButton *noToAllButton = msgBox.addButtonSecond(QDialogButtonBox::NoToAll);
+ QAbstractButton *abortButton = msgBox.addButtonSecond(tr("Abort"), QDialogButtonBox::DestructiveRole);
+ QAbstractButton *newNameButton = msgBox.addButtonFirst(tr("New Name"), QDialogButtonBox::AcceptRole);
QAbstractButton *askButton = 0;
+ QAbstractButton *skipDirButton = 0;
if (dirOverDir) {
- msgBox.setText(tr("Directory %1 already exists. Overwrite the files inside?").arg(fileName));
- askButton = msgBox.addButton(tr("Ask"), QMessageBox::AcceptRole);
+ msgBox.setText(tr("Directory %1 already exists. Overwrite the files inside?")
+ .arg(FileOperator::shortenPath(fileName)));
+ askButton = msgBox.addButtonFirst(tr("Ask"), QDialogButtonBox::AcceptRole);
+ skipDirButton = msgBox.addButtonSecond(tr("Skip"), QDialogButtonBox::NoRole);
} 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();
- if (msgBox.clickedButton() == abortButton) {
+ if (msgBox.clickedButton == abortButton) {
manipulator->setResponse(ABORT);
- } else if (msgBox.clickedButton() == yesButton) {
+ } else if (msgBox.clickedButton == yesButton) {
manipulator->setResponse(OVERWRITE);
- } else if (msgBox.clickedButton() == yesToAllButton) {
+ } else if (msgBox.clickedButton == yesToAllButton) {
manipulator->setResponse(OVERWRITE, true);
- } else if (msgBox.clickedButton() == noButton) {
+ } else if (msgBox.clickedButton == noButton) {
manipulator->setResponse(KEEP);
- } else if (msgBox.clickedButton() == noToAllButton) {
+ } else if (msgBox.clickedButton == noToAllButton) {
manipulator->setResponse(KEEP, true);
- } else if (msgBox.clickedButton() == askButton) {
- manipulator->setResponse(NONE, true);
+ } else if (msgBox.clickedButton == askButton) {
+ manipulator->setResponse(ASK);
+ } else if (msgBox.clickedButton == newNameButton) {
+ manipulator->setResponse(NONE);
+ } else if (msgBox.clickedButton == skipDirButton) {
+ manipulator->setResponse(SKIP_DIR);
}
}
+void FileOperator::showInputFilenamePrompt(FileManipulatorThread* manipulator,
+ const QFileInfo &file,
+ const bool dir)
+{
+ bool ok;
+ QString prompt, error;
+
+ if (dir) {
+ prompt = tr("Enter the new directory name.");
+ } else {
+ prompt = tr("Enter the new file name.");
+ }
+
+ manipulator->mutex.lock();
+
+ manipulator->newNameFromDialog = "";
+ QString text = file.fileName();
+
+
+ while (true) {
+ text = QInputDialog::getText(this, QString(), prompt + error, QLineEdit::Normal, text, &ok);
+
+ if (!ok) break;
+
+ error = "";
+ if (text.contains(QRegExp("[\"*/:<>?\\\\|]"))) {
+ error = "<small><br/><font color = 'red'>" + tr("The name cannot contain any of the following characters: ") +
+ "\"*/:<>?\\|</font></small>";
+ } else if (ok && !text.isEmpty()) {
+ QFileInfo info(file.path() + "/" + text);
+ manipulator->newNameFromDialog = info.absoluteFilePath();
+ break;
+ }
+ }
+
+ manipulator->mutex.unlock();
+ manipulator->waitCond.wakeAll();
+}
+
+
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(showInputFilenamePrompt(FileManipulatorThread*, const QFileInfo&, bool)),
+ this, SLOT(showInputFilenamePrompt(FileManipulatorThread*, const QFileInfo&, bool)));
connect(thread, SIGNAL(finished(FileManipulatorThread*)),
this, SLOT(remove(FileManipulatorThread*)));
connect(thread, SIGNAL(setBarSize(FileManipulatorThread*, unsigned int)),
connect(thread, SIGNAL(updateProgress(FileManipulatorThread*, int)),
this, SLOT(updateProgress(FileManipulatorThread*, int)));
- thread->widget->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(1);
+ progressBar->setValue(0);
+ progressBar->setMinimum(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() {
+ if (!abort && progressBar->value() < progressBar->maximum()) {
+ std::cout << "WARNING: deleting a progressbar which's value " << progressBar->value() <<
+ " has not reached maximum of " << progressBar->maximum() << std::endl;
+ }
+ delete progressBar;
}
}
-bool FileManipulatorThread::remove(QString &fileName, const bool ignoreDirNotEmpty) {
- return remove(QFileInfo(fileName), ignoreDirNotEmpty);
+bool FileManipulatorThread::remove(QString &fileName, const bool doUpdates) {
+ return remove(QFileInfo(fileName), doUpdates);
}
-bool FileManipulatorThread::remove(const QFileInfoList &files, const bool ignoreDirNotEmpty) {
+bool FileManipulatorThread::remove(const QFileInfoList &files, const bool doUpdates) {
bool res = true;
for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
- if (!remove(*it, ignoreDirNotEmpty)) res = false;
+ if (!remove(*it, doUpdates)) res = false;
if (abort) break;
}
return res;
}
-bool FileManipulatorThread::remove(const QFileInfo &file, const bool ignoreDirNotEmpty) {
+bool FileManipulatorThread::remove(const QFileInfo &file, const bool doUpdates) {
+ std::cout << "DELETING " << file.absoluteFilePath().toStdString() << std::endl;
+
QString path = file.absoluteFilePath();
- QFSFileEngine engine(path);
- if (file.isDir()) {
- QFileInfoList list = listDirFiles(path);
+ if (removeExcludeFiles.contains(path)) {
+ if (doUpdates) updateProgress(1);
+ return false;
+ }
- if (ignoreDirNotEmpty && list.size()) return true;
+ QFSFileEngine engine(path);
- if (!remove(list, ignoreDirNotEmpty)) return false;
+ if (doUpdates) updateFile(path);
- ERROR_PROMPT(!engine.rmdir(path, false),
- tr("Error deleting directory %1.").arg(path))
+ if (file.isDir()) {
+ if (!remove(listDirFiles(path), doUpdates)) {
+ if (doUpdates) updateProgress(1);
+ return false;
+ }
+
+ if (!listDirFiles(path).size()) {
+ ERROR_PROMPT(!engine.rmdir(path, false), tr("Error deleting directory %1."), path)
+ }
} else {
- ERROR_PROMPT(!engine.remove(),
- tr("Error deleting file %1.").arg(path))
+ ERROR_PROMPT(!engine.remove(), tr("Error deleting file %1."), path)
}
+ if (!abort && doUpdates) updateProgress(1);
+
if (abort || response == FileOperator::IGNORE) return false;
return true;
}
-void FileManipulatorThread::copy(const QFileInfo &file, const bool removeAfterCopy) {
- std::cout << (removeAfterCopy ? "MOVING " : "COPYING ") << file.absoluteFilePath().toStdString()
+void FileManipulatorThread::copy(const QFileInfo &file) {
+ std::cout << "COPYING " << file.absoluteFilePath().toStdString()
<< " to " << dest.absolutePath().toStdString() << std::endl;
QString path(file.absoluteFilePath());
- QString newPath(dest.absolutePath() + "/" + file.fileName());
QFSFileEngine engine(path);
- QFSFileEngine newEngine(newPath);
- QFileInfo newFile(newPath);
+ QFileInfo newFile(dest.absolutePath() + "/" + file.fileName());
updateFile(path);
OVERWRITE_PROMPT(file, newFile)
}
- if (abort) return;
+ QString newPath(newFile.absoluteFilePath());
+ QFSFileEngine newEngine(newPath);
- // this loop is here only to allow easily breaking out to the end (and remove the source file/dir)
- while (1) {
- if (response == FileOperator::KEEP) {
- updateProgress(fileSizeMap[path]);
- break;
- }
+ if (abort) return;
+ if (file.isDir()) {
+ // save the overwrite response, because the response variable will get ovewritten in remove(...)
FileOperator::Response overwriteResponse = response;
- if (file.isDir()) {
- if (newFile.exists() && !newFile.isDir()) {
- if(!remove(newPath)) {
- updateProgress(fileSizeMap[path]);
- break;
- }
- newFile = QFileInfo(newPath);
+ if (newFile.exists() && !newFile.isDir()) {
+ // overwriting a file, so check for KEEP and handle it
+ if (response == FileOperator::KEEP) {
+ updateProgress(fileSizeMap[path]);
+ removeExcludeFiles.insert(path);
+ return;
}
- if (!newFile.exists()) {
- ERROR_PROMPT_XP(!engine.mkdir(newPath, false),
- tr("Error creating directory %1.").arg(newPath),
- updateProgress(fileSizeMap[path]),
- break)
+ // if it should not be kept, remove it and return on failure
+ if(!remove(newPath)) {
+ updateProgress(fileSizeMap[path]);
+ return;
+ }
+ // create new info since we deleted the file - is it needed?
+ newFile = QFileInfo(newPath);
+ } else {
+ // overwriting a directory - response KEEP means to keep the files inside,
+ // SKIP_DIR means to skip the dir completely
+ if (response == FileOperator::SKIP_DIR) {
+ updateProgress(fileSizeMap[path]);
+ removeExcludeFiles.insert(path);
+ return;
}
+ }
- updateProgress(1);
-
- QDir destBackup = dest;
- dest = newPath;
+ if (!newFile.exists()) {
+ SPECIAL_COPY_ERROR_PROMPT(!engine.mkdir(newPath, false),
+ tr("Error creating directory %1."), newPath)
+ }
- FileOperator::Response tmpResp = overwriteAll;
- overwriteAll = overwriteResponse;
+ // we've done the job with the dir, so update progress and recurse into the dir
+ updateProgress(1);
+
+ // change the dest for the recursion
+ QDir destBackup = dest;
+ dest = newPath;
- processFiles(listDirFiles(path));
+ // and set overwriteAll to the response we got a while ago
+ // because it applies to the files inside the dir
+ FileOperator::Response tmpResp = overwriteAll;
+ overwriteAll = overwriteResponse;
- overwriteAll = tmpResp;
+ processFiles(listDirFiles(path));
- ERROR_PROMPT(!newEngine.setPermissions(file.permissions()),
- tr("Error setting permissions for directory %1.").arg(newPath))
+ overwriteAll = tmpResp;
- if (abort) return;
+ ERROR_PROMPT(!newEngine.setPermissions(file.permissions()),
+ tr("Error setting permissions for directory %1."), newPath)
- dest = destBackup;
- } else {
- ERROR_PROMPT_XP(engine.isSequential(),
- tr("Cannot copy sequential file %1.").arg(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),
- updateProgress(fileSizeMap[path]),
- break)
- }
+ if (abort) return;
- ERROR_PROMPT_XP(!engine.open(QIODevice::ReadOnly),
- tr("Error reading file %1.").arg(path),
- updateProgress(fileSizeMap[path]),
- break)
+ dest = destBackup;
+ } else {
+ if (response == FileOperator::KEEP) {
+ updateProgress(fileSizeMap[path]);
+ removeExcludeFiles.insert(path);
+ return;
+ }
- bool ignore = false;
- while (!abort && !ignore) {
- engine.seek(0);
+ SPECIAL_COPY_ERROR_PROMPT(engine.isSequential(), tr("Cannot copy sequential file %1."), path)
- ERROR_PROMPT(!newEngine.open(QIODevice::WriteOnly | QIODevice::Truncate),
- tr("Error writing file %1.").arg(newPath))
+ if (newFile.exists() && newFile.isDir()) {
+ SPECIAL_COPY_ERROR_PROMPT(!remove(newPath),
+ tr("Cannot replace directory %1 due to previous errors."), newPath)
+ }
- if (abort || response == FileOperator::IGNORE) {
- if (response == FileOperator::IGNORE) {
- updateProgress(fileSizeMap[path] - fileValue);
- ignore = true;
- }
- break;
+ SPECIAL_COPY_ERROR_PROMPT(!engine.open(QIODevice::ReadOnly), tr("Error reading file %1."), path)
+
+ bool ignore = false, newFileWritten = false;
+ while (!abort && !ignore) {
+ engine.seek(0);
+ fileValue = 0;
+
+ ERROR_PROMPT(!newEngine.open(QIODevice::WriteOnly | QIODevice::Truncate),
+ tr("Error writing file %1."), newPath)
+
+ if (abort || response == FileOperator::IGNORE) {
+ if (response == FileOperator::IGNORE) {
+ updateProgress(fileSizeMap[path]);
+ removeExcludeFiles.insert(path);
+ ignore = true;
}
+ break;
+ }
- bool error = false;
- char block[4096];
- 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));
- } else {
- SHOW_ERROR_PROMPT(tr("Error while writing to file %1.").arg(newPath));
- }
+ newFileWritten = true;
+
+ bool error = false;
+ char block[BLOCK_SIZE];
+ 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."), path);
+ } else {
+ SHOW_ERROR_PROMPT(tr("Error while writing to file %1."), newPath);
+ }
- if (!abort) {
- if (response == FileOperator::IGNORE) {
- updateProgress(fileSizeMap[path] - fileValue);
- ignore = true;
- } else {
- updateProgress(-fileValue);
- }
+ if (!abort) {
+ if (response == FileOperator::IGNORE) {
+ updateProgress(fileSizeMap[path] - fileValue);
+ removeExcludeFiles.insert(path);
+ ignore = true;
+ } else {
+ updateProgress(-fileValue);
}
- error = true;
- break;
}
-
- updateProgress(1);
+ error = true;
+ break;
}
- if (!error) break;
+ updateProgress(1);
}
- engine.close();
- newEngine.close();
+ if (!error) break;
+ }
+
+ engine.close();
+ newEngine.close();
- if (abort || ignore) {
+ if (abort || ignore) {
+ if (newFileWritten) {
newEngine.remove();
- } else {
- ERROR_PROMPT(!newEngine.setPermissions(file.permissions()),
- tr("Error setting permissions for file %1.").arg(newPath))
}
+ } else {
+ ERROR_PROMPT(!newEngine.setPermissions(file.permissions()),
+ tr("Error setting permissions for file %1."), newPath)
}
-
- break;
}
-
- if (removeAfterCopy && !abort) remove(path, true);
}
-unsigned int FileManipulatorThread::countFiles(const QFileInfoList &files) {
+unsigned int FileManipulatorThread::calculateFileSize(const QFileInfoList &files,
+ const bool count,
+ const bool addSize)
+{
unsigned int res = 0;
for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
- unsigned int size = 1;
+ unsigned int size = 0;
if (it->isDir()) {
- size += countFiles(listDirFiles(it->absoluteFilePath()));
+ size += calculateFileSize(listDirFiles(it->absoluteFilePath()), count, addSize);
}
- res += size;
- fileSizeMap[it->absoluteFilePath()] = size;
- }
-
- return res;
-}
-
-
-unsigned int FileManipulatorThread::calculateFileSize(const QFileInfoList &files) {
- unsigned int res = 0;
-
- for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
- unsigned int size = 1;
+ if (addSize) {
+ if (it->isDir()) {
+ ++size;
+ } else {
+ size += ceil(static_cast<float>(it->size()) / BLOCK_SIZE);
+ }
+ fileSizeMap[it->absoluteFilePath()] = size;
+ }
- if (it->isDir()) {
- size += calculateFileSize(listDirFiles(it->absoluteFilePath()));
- } else {
- size = ceil(static_cast<float>(it->size()) / 4096);
+ if (count) {
+ ++size;
}
res += size;
- fileSizeMap[it->absoluteFilePath()] = size;
}
return res;
}
-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 progressbar maximum (" << progressBar->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");
}
void DeleteThread::run() {
mutex.lock();
- setBarSize(countFiles(files));
+ setBarSize(calculateFileSize(files, true));
processFiles(files);
void DeleteThread::perform(const QFileInfo &file) {
- std::cout << "DELETING " << file.absoluteFilePath().toStdString() << std::endl;
-
- QString path = file.absoluteFilePath();
- QFSFileEngine engine(path);
-
- if (file.isDir()) {
- processFiles(listDirFiles(path));
+ remove(file, true);
+}
- if (!listDirFiles(path).size()) {
- ERROR_PROMPT(!engine.rmdir(path, false),
- tr("Error deleting directory %1.").arg(path))
- }
- } else {
- ERROR_PROMPT(!engine.remove(),
- tr("Error deleting file %1.").arg(path))
- }
- if (!abort) updateProgress(1);
+CopyThread::CopyThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {
+ barText = tr("copying %1");
}
void CopyThread::run() {
mutex.lock();
- setBarSize(calculateFileSize(files));
+ setBarSize(calculateFileSize(files, false, true));
processFiles(files);
void CopyThread::perform(const QFileInfo &file) {
- copy(file, false);
+ copy(file);
+}
+
+
+MoveThread::MoveThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {
+ barText = tr("moving %1");
}
for (int i = 0; i < files.size(); ++i) {
QString path = files[i].absoluteFilePath();
QFSFileEngine engine(path);
- QString newPath = dest.absolutePath() + "/" + files[i].fileName();
+ QFileInfo newFile(dest.absolutePath() + "/" + files[i].fileName());
updateFile(path);
- OVERWRITE_PROMPT(files[i], QFileInfo(newPath))
+ OVERWRITE_PROMPT(files[i], newFile)
- if (response == FileOperator::KEEP) {
- remove(path);
- if (abort) break;
- updateProgress(1);
- continue;
+ // if we are owerwriting dir over a dir, we will get SKIP_DIR
+ // as a response from OVERWRITE_PROMT meaning we should skip it
+ // (KEEP would mean to keep the files inside)
+ if (files[i].isDir() && newFile.exists() && newFile.isDir()) {
+ if (response == FileOperator::SKIP_DIR) {
+ if (abort) break;
+ updateProgress(1);
+ removeExcludeFiles.insert(path);
+ continue;
+ }
+ } else {
+ if (response == FileOperator::KEEP) {
+ if (abort) break;
+ updateProgress(1);
+ removeExcludeFiles.insert(path);
+ continue;
+ }
}
+ QString newPath(newFile.absoluteFilePath());
+ QFSFileEngine newEngine(newPath);
+
while (!abort && !engine.rename(newPath)) {
// source and target are on different partitions
// this should happen on the first file, unless some are skipped by overwrite prompt
// we calculate the actual file sizes, because from now on copy & remove takes over
if (errno == EXDEV) {
- setBarSize(barValue + calculateFileSize(files));
-
- FileOperator::Response tmpResp = overwriteAll;
overwriteAll = response;
// hack: we already checked the first file we are sending to processFiles(...)
// so we don't want to ask about this one again
if (overwriteAll == FileOperator::NONE) overwriteAll = FileOperator::DONT_ASK_ONCE;
- processFiles(files.mid(i));
+ QFileInfoList remainingFiles = files.mid(i);
- overwriteAll = tmpResp;
+ setBarSize(barValue + calculateFileSize(remainingFiles, true, true));
+
+ processFiles(remainingFiles);
+
+ barText = tr("deleting %1");
+
+ remove(remainingFiles, true);
// just to quit the loops, we are done
abort = true;
overwriteAll = tmpResp;
- ERROR_PROMPT(!engine.rmdir(path, false), tr("Error deleting directory %1.").arg(path))
+ remove(files[i]);
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;
void MoveThread::perform(const QFileInfo &file) {
- copy(file, true);
+ copy(file);
}