From fc4f4d99f9ab90e0bcfb3e6571970c722ece7647 Mon Sep 17 00:00:00 2001 From: Lukas Hrazky Date: Fri, 30 Jul 2010 22:12:23 +0200 Subject: [PATCH] option to enter new name in overwrite dialog Signed-off-by: Lukas Hrazky --- src/addressbar.cpp | 1 + src/fileoperator.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++-------- src/fileoperator.h | 24 +++++++++++--- 3 files changed, 94 insertions(+), 17 deletions(-) diff --git a/src/addressbar.cpp b/src/addressbar.cpp index 8ef21fb..0bc1038 100644 --- a/src/addressbar.cpp +++ b/src/addressbar.cpp @@ -18,6 +18,7 @@ #include "addressbar.h" #include "fileoperator.h" + AddressBar::AddressBar(QWidget *parent) : QLineEdit(parent) { setMaximumHeight(60); setContentsMargins(-4, -4, -4, -4); diff --git a/src/fileoperator.cpp b/src/fileoperator.cpp index 90cb7da..a779a87 100644 --- a/src/fileoperator.cpp +++ b/src/fileoperator.cpp @@ -74,16 +74,24 @@ { \ 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; \ } @@ -92,6 +100,7 @@ FileOperator::FileOperator(QWidget *parent) : QWidget(parent) { layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); setLayout(layout); + qRegisterMetaType("QFileInfo"); } @@ -227,6 +236,7 @@ void FileOperator::showOverwritePrompt( 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; @@ -252,13 +262,55 @@ void FileOperator::showOverwritePrompt( } 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 = "
" + tr("The name cannot contain any of the following characters: ") + + "\"*/:<>?\\|
"; + } 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); @@ -288,6 +340,8 @@ void FileOperator::caterNewThread(FileManipulatorThread *thread) { 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)), @@ -295,8 +349,6 @@ void FileOperator::caterNewThread(FileManipulatorThread *thread) { connect(thread, SIGNAL(updateProgress(FileManipulatorThread*, int)), this, SLOT(updateProgress(FileManipulatorThread*, int))); - thread->progressBar->setValue(0); - layout()->addWidget(thread->progressBar); thread->start(QThread::LowestPriority); } @@ -317,7 +369,9 @@ FileManipulatorThread::FileManipulatorThread(const QFileInfoList files, QDir des 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); @@ -428,10 +482,8 @@ void FileManipulatorThread::copy(const QFileInfo &file) { << " 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); @@ -442,6 +494,9 @@ void FileManipulatorThread::copy(const QFileInfo &file) { OVERWRITE_PROMPT(file, newFile) } + QString newPath(newFile.absoluteFilePath()); + QFSFileEngine newEngine(newPath); + if (abort) return; if (file.isDir()) { @@ -732,13 +787,15 @@ void MoveThread::rename(const QFileInfoList &files, const QDir &dest) { 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; @@ -755,6 +812,9 @@ void MoveThread::rename(const QFileInfoList &files, const QDir &dest) { } } + 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 diff --git a/src/fileoperator.h b/src/fileoperator.h index 8a8430d..4d2563b 100644 --- a/src/fileoperator.h +++ b/src/fileoperator.h @@ -37,7 +37,7 @@ class FileOperator : public QWidget { 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); @@ -55,6 +55,9 @@ public slots: 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); @@ -80,6 +83,10 @@ public: 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); @@ -101,31 +108,40 @@ protected: 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 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 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); -- 1.7.9.5