{ \
response = FileOperator::NONE; \
\
- if (newFile.exists()) { \
+ while (response == FileOperator::NONE && 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); \
+ 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");
}
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;
} else if (msgBox.clickedButton == noToAllButton) {
manipulator->setResponse(KEEP, true);
} else if (msgBox.clickedButton == askButton) {
- manipulator->setResponse(NONE, true);
+ 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) {
manipulator->wait();
layout()->removeWidget(manipulator->progressBar);
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->progressBar->setValue(0);
-
layout()->addWidget(thread->progressBar);
thread->start(QThread::LowestPriority);
}
fileValue(0)
{
memset(ignoreAll, false, sizeof(ignoreAll));
- progressBar->setMaximum(0);
+ progressBar->setMaximum(1);
+ progressBar->setValue(0);
+ progressBar->setMinimum(0);
QFont barFont = progressBar->font();
barFont.setPointSize(12);
progressBar->setFont(barFont);
<< " 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)
}
+ QString newPath(newFile.absoluteFilePath());
+ QFSFileEngine newEngine(newPath);
+
if (abort) return;
if (file.isDir()) {
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(newPath);
+ QFileInfo newFile(dest.absolutePath() + "/" + files[i].fileName());
updateFile(path);
OVERWRITE_PROMPT(files[i], newFile)
+ // 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;
}
}
+ 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
public:
// DONT_ASK_ONCE is a hackish way to avoid asking twice to overwrite the same directory when moving
- enum Response{NONE, ABORT, RETRY, IGNORE, KEEP, OVERWRITE, SKIP_DIR, DONT_ASK_ONCE};
+ enum Response{NONE, ABORT, RETRY, IGNORE, KEEP, OVERWRITE, SKIP_DIR, ASK, DONT_ASK_ONCE};
FileOperator(QWidget *parent = 0);
void showOverwritePrompt(FileManipulatorThread* manipulator,
const QString &fileName,
const bool dirOverDir);
+ void showInputFilenamePrompt(FileManipulatorThread* manipulator,
+ const QFileInfo &fileName,
+ const bool dirOverDir);
void remove(FileManipulatorThread* manipulator);
void setBarSize(FileManipulatorThread* manipulator, unsigned int size);
QProgressBar *progressBar;
time_t startTime;
+ QMutex mutex;
+ QWaitCondition waitCond;
+ // the new name entered from the overwrite dialog
+ QString newNameFromDialog;
protected:
void processFiles(const QFileInfoList &files);
void updateProgress(int value);
void updateFile(const QString &name);
+ // files to process by the operation
const QFileInfoList files;
+ // destination for files - changes as the operation recurses into directories
QDir dest;
+ // responses from the dialog prompts (error and overwrite)
FileOperator::Response response;
FileOperator::Response overwriteAll;
+ // a flag to abort the operation
bool abort;
+ // an array indicating whether to always ignore the error of index errno
bool ignoreAll[256];
// set of files that won't be deleted by the remove(...) functions
// used when move(...) would not overwrite target file to ensure the source file doesn't get deleted
QSet<QString> removeExcludeFiles;
+ // A map of file paths to their size. Not the actual size, but what is calculated for the
+ // purpose of the progressbar for the given operation. So either fileSize/BLOCK_SIZE or simply
+ // 1 for a file and file count for dirs (or both for copy&delete)
QMap<QString, qint64> fileSizeMap;
- QMutex mutex;
- QWaitCondition waitCond;
-
+ // the name of the file thats being processed (for progressBar) and the text of the progressBar (the format)
QString fileName, barText;
+ // stamp of the last ETA recalculation - done every second
time_t lastTimeUpdate;
char timeBuf[10];
+ // progress information of the bar and for the current file
unsigned int barSize, barValue, fileSize, fileValue;
signals:
void showErrorPrompt(FileManipulatorThread*, const QString&, const QString&, const int);
void showOverwritePrompt(FileManipulatorThread*, const QString&, const bool);
+ void showInputFilenamePrompt(FileManipulatorThread*, const QFileInfo&, const bool);
void finished(FileManipulatorThread*);
void setBarSize(FileManipulatorThread*, unsigned int);
void updateProgress(FileManipulatorThread*, int);