1 // case - file manager for N900
2 // Copyright (C) 2010 Lukas Hrazky <lukkash@email.cz>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "fileoperator.h"
22 #include <QMessageBox>
23 #include <QHBoxLayout>
34 #define BLOCK_SIZE 524288
39 emit operationPaused(this); \
44 #define SHOW_ERROR_PROMPT(promptString, fileName) \
45 response = FileOperator::NONE; \
46 if (ignoreAll[errno]) { \
47 response = FileOperator::IGNORE; \
50 char *realBuf = buf; \
52 strcpy(buf, tr("File is sequential").toStdString().c_str()); \
54 realBuf = strerror_r(errno, buf, 255); \
56 emit showErrorPrompt(this, promptString + " " + realBuf + ".", fileName, errno); \
61 #define ERROR_PROMPT(operation, promptString, fileName) \
63 response = FileOperator::NONE; \
64 while (!abort && operation) { \
65 SHOW_ERROR_PROMPT(promptString, fileName) \
66 if (response == FileOperator::IGNORE) { \
74 #define SPECIAL_COPY_ERROR_PROMPT(operation, promptString, fileName) \
76 ERROR_PROMPT(operation, promptString, fileName) \
77 if (abort || response == FileOperator::IGNORE) { \
79 updateProgress(fileSizeMap[path]); \
80 removeExcludeFiles.insert(path); \
87 #define OVERWRITE_PROMPT(file, newFile) \
89 response = FileOperator::NONE; \
91 while (!abort && response == FileOperator::NONE && newFile.exists()) { \
92 if (overwriteAll != FileOperator::NONE) { \
93 response = overwriteAll; \
95 emit showOverwritePrompt(this, newFile.absoluteFilePath(), \
96 newFile.isDir() && file.isDir()); \
100 else if (response == FileOperator::NONE) { \
101 emit showInputFilenamePrompt(this, newFile, file.isDir()); \
103 if (newNameFromDialog.size()) { \
104 newFile.setFile(newNameFromDialog); \
109 if (response == FileOperator::ASK) response = FileOperator::NONE; \
113 FileOperator::FileOperator(QWidget *parent) : QWidget(parent) {
114 QHBoxLayout *layout = new QHBoxLayout;
115 layout->setContentsMargins(0, 0, 0, 0);
116 layout->setSpacing(1);
118 qRegisterMetaType<QFileInfo>("QFileInfo");
119 loadOperationIcons(palette(), "delete_small", deleteIcon, inverseDeleteIcon);
120 loadOperationIcons(palette(), "copy_small", copyIcon, inverseCopyIcon);
121 loadOperationIcons(palette(), "move_small", moveIcon, inverseMoveIcon);
125 QString FileOperator::shortenPath(const QString &path) {
126 QString homePath = QFSFileEngine::homePath();
128 if (path.indexOf(homePath, 0) == 0) {
129 QString result = path;
131 result.replace(0, homePath.size(), "~");
139 QString FileOperator::unwindPath(const QString &path) {
140 QString result = path;
141 // if ~ is the first character and / or nothing follows it, replace with home dir
142 if (path == "~" || path.indexOf("~/", 0) == 0) {
143 QString homePath = QFSFileEngine::homePath();
144 result.replace(0, 1, homePath);
145 // in case someone wants to enter a dir called ~ in the current dir, he can escape it with \~
146 } else if (path == "\\~" || path.indexOf("\\~/", 0) == 0) {
147 result.replace(0, 2, "~");
154 void FileOperator::deleteFiles(const QFileInfoList &files) {
156 if (files.size() == 1) {
157 title = tr("Delete file");
158 desc = tr("Are you sure you want to delete %1?")
159 .arg(FileOperator::shortenPath(files[0].absoluteFilePath()));
161 title = tr("Delete files");
162 desc = tr("You are about to delete %1 files. Are you sure you want to continue?").arg(files.size());
165 int confirm = QMessageBox::warning(
173 if(confirm == QMessageBox::Yes) {
174 DeleteThread *t = new DeleteThread(files);
175 t->progressBar->setIcons(deleteIcon, inverseDeleteIcon);
181 void FileOperator::copyFiles(const QFileInfoList &files, QDir &destination) {
183 if (files.size() == 1) {
184 title = tr("Copy file");
185 desc = tr("Are you sure you want to copy %1 to %2?")
186 .arg(FileOperator::shortenPath(files[0].absoluteFilePath()))
187 .arg(FileOperator::shortenPath(destination.absolutePath()));
189 title = tr("Copy files");
190 desc = tr("You are about to copy %1 files to %2. Are you sure you want to continue?")
191 .arg(files.size()).arg(FileOperator::shortenPath(destination.absolutePath()));
194 int confirm = QMessageBox::warning(
202 if(confirm == QMessageBox::Yes) {
203 CopyThread *t = new CopyThread(files, destination);
204 t->progressBar->setIcons(copyIcon, inverseCopyIcon);
205 t->progressBar->fromText = shortenPath(files[0].absolutePath());
206 t->progressBar->toText = FileOperator::shortenPath(destination.absolutePath());
212 void FileOperator::moveFiles(const QFileInfoList &files, QDir &destination) {
213 // for move we don't wanna move to the same dir
214 if (files[0].absolutePath() == destination.absolutePath()) return;
217 if (files.size() == 1) {
218 title = tr("Move file");
219 desc = tr("Are you sure you want to move %1 to %2?")
220 .arg(FileOperator::shortenPath(files[0].absoluteFilePath()))
221 .arg(FileOperator::shortenPath(destination.absolutePath()));
223 title = tr("Move files");
224 desc = tr("You are about to move %1 files to %2. Are you sure you want to continue?")
225 .arg(files.size()).arg(FileOperator::shortenPath(destination.absolutePath()));
228 int confirm = QMessageBox::warning(
236 if(confirm == QMessageBox::Yes) {
237 MoveThread *t = new MoveThread(files, destination);
238 t->progressBar->setIcons(moveIcon, inverseMoveIcon);
239 t->progressBar->fromText = shortenPath(files[0].absolutePath());
240 t->progressBar->toText = shortenPath(destination.absolutePath());
246 void FileOperator::showErrorPrompt(FileManipulatorThread* manipulator,
247 const QString &message,
248 const QString &fileName,
252 QAbstractButton *cancelButton = msgBox.addButton(QMessageBox::Cancel);
253 QAbstractButton *abortButton = msgBox.addButton(tr("Abort"), QMessageBox::DestructiveRole);
254 QAbstractButton *retryButton = msgBox.addButton(QMessageBox::Retry);
255 QAbstractButton *ignoreButton = msgBox.addButton(QMessageBox::Ignore);
256 QAbstractButton *ignoreAllButton = msgBox.addButton(tr("Ignore All"), QMessageBox::AcceptRole);
257 msgBox.setText(message.arg(FileOperator::shortenPath(fileName)));
261 if (msgBox.clickedButton() == cancelButton) {
262 manipulator->pause = true;
263 manipulator->setResponse(RETRY);
264 } else if (msgBox.clickedButton() == abortButton) {
265 manipulator->setResponse(ABORT);
266 } else if (msgBox.clickedButton() == retryButton) {
267 manipulator->setResponse(RETRY);
268 } else if (msgBox.clickedButton() == ignoreButton) {
269 manipulator->setResponse(IGNORE);
270 } else if (msgBox.clickedButton() == ignoreAllButton) {
271 manipulator->setResponse(IGNORE, true, err);
276 void FileOperator::showOverwritePrompt(
277 FileManipulatorThread* manipulator,
278 const QString &fileName,
279 const bool dirOverDir)
282 QAbstractButton *yesButton = msgBox.addButtonFirst(QDialogButtonBox::Yes);
283 QAbstractButton *yesToAllButton = msgBox.addButtonFirst(QDialogButtonBox::YesToAll);
284 QAbstractButton *noButton = msgBox.addButtonSecond(QDialogButtonBox::No);
285 QAbstractButton *noToAllButton = msgBox.addButtonSecond(QDialogButtonBox::NoToAll);
286 QAbstractButton *abortButton = msgBox.addButtonSecond(tr("Abort"), QDialogButtonBox::DestructiveRole);
287 QAbstractButton *newNameButton = msgBox.addButtonFirst(tr("New Name"), QDialogButtonBox::AcceptRole);
288 QAbstractButton *askButton = 0;
289 QAbstractButton *skipDirButton = 0;
292 msgBox.setText(tr("Directory %1 already exists. Overwrite the files inside?")
293 .arg(FileOperator::shortenPath(fileName)));
294 askButton = msgBox.addButtonFirst(tr("Ask"), QDialogButtonBox::AcceptRole);
295 skipDirButton = msgBox.addButtonSecond(tr("Skip"), QDialogButtonBox::NoRole);
297 msgBox.setText(tr("File %1 already exists. Overwrite?").arg(FileOperator::shortenPath(fileName)));
302 if (msgBox.clickedButton == 0) {
303 manipulator->pause = true;
304 manipulator->setResponse(NONE);
305 } else if (msgBox.clickedButton == abortButton) {
306 manipulator->setResponse(ABORT);
307 } else if (msgBox.clickedButton == yesButton) {
308 manipulator->setResponse(OVERWRITE);
309 } else if (msgBox.clickedButton == yesToAllButton) {
310 manipulator->setResponse(OVERWRITE, true);
311 } else if (msgBox.clickedButton == noButton) {
312 manipulator->setResponse(KEEP);
313 } else if (msgBox.clickedButton == noToAllButton) {
314 manipulator->setResponse(KEEP, true);
315 } else if (msgBox.clickedButton == askButton) {
316 manipulator->setResponse(ASK);
317 } else if (msgBox.clickedButton == newNameButton) {
318 manipulator->setResponse(NONE);
319 } else if (msgBox.clickedButton == skipDirButton) {
320 manipulator->setResponse(SKIP_DIR);
325 void FileOperator::showInputFilenamePrompt(FileManipulatorThread* manipulator,
326 const QFileInfo &file,
330 QString prompt, error;
333 prompt = tr("Enter the new directory name.");
335 prompt = tr("Enter the new file name.");
338 manipulator->mutex.lock();
340 manipulator->newNameFromDialog = "";
341 QString text = file.fileName();
344 text = QInputDialog::getText(this, QString(), prompt + error, QLineEdit::Normal, text, &ok);
349 if (text.contains(QRegExp("[\"*/:<>?\\\\|]"))) {
350 error = "<small><br/><font color = 'red'>" + tr("The name cannot contain any of the following characters: ") +
351 "\"*/:<>?\\|</font></small>";
352 } else if (ok && !text.isEmpty()) {
353 QFileInfo info(file.path() + "/" + text);
354 manipulator->newNameFromDialog = info.absoluteFilePath();
359 manipulator->mutex.unlock();
364 void FileOperator::remove(FileManipulatorThread* manipulator) {
366 layout()->removeWidget(manipulator->progressBar);
367 manipulatorList.removeAll(manipulator);
372 void FileOperator::setBarSize(FileManipulatorThread* manipulator, unsigned int size) {
373 manipulator->progressBar->setMinimum(0);
374 manipulator->progressBar->setMaximum(size);
378 void FileOperator::updateProgress(FileManipulatorThread* manipulator, int value) {
379 manipulator->setText(value);
383 void FileOperator::updateMainText(FileManipulatorThread* manipulator, const QString &text) {
384 manipulator->progressBar->mainText = text;
385 manipulator->progressBar->mainText.remove(0, manipulator->progressBar->fromText.size() + 1);
386 manipulator->progressBar->repaint();
390 void FileOperator::showPaused(FileManipulatorThread* manipulator) {
391 manipulator->progressBar->paused = true;
392 manipulator->progressBar->repaint();
396 void FileOperator::togglePauseOperation(FileManipulatorThread* manipulator) {
397 if (manipulator->pause) {
398 manipulator->pause = false;
399 manipulator->progressBar->paused = false;
400 manipulator->progressBar->repaint();
403 manipulator->pause = true;
408 void FileOperator::abortOperation(FileManipulatorThread* manipulator) {
409 int confirm = QMessageBox::warning(
411 tr("Abort operation"),
412 tr("Are you sure you want to abort the operation?"),
417 if(confirm == QMessageBox::Yes) {
418 manipulator->abort = true;
419 manipulator->pause = false;
425 void FileOperator::caterNewThread(FileManipulatorThread *thread) {
426 manipulatorList.append(thread);
428 connect(thread, SIGNAL(showErrorPrompt(FileManipulatorThread*, const QString&, const QString&, const int)),
429 this, SLOT(showErrorPrompt(FileManipulatorThread*, const QString&, const QString&, const int)));
430 connect(thread, SIGNAL(showOverwritePrompt(FileManipulatorThread*, const QString&, bool)),
431 this, SLOT(showOverwritePrompt(FileManipulatorThread*, const QString&, bool)));
432 connect(thread, SIGNAL(showInputFilenamePrompt(FileManipulatorThread*, const QFileInfo&, bool)),
433 this, SLOT(showInputFilenamePrompt(FileManipulatorThread*, const QFileInfo&, bool)));
434 connect(thread, SIGNAL(finished(FileManipulatorThread*)),
435 this, SLOT(remove(FileManipulatorThread*)));
436 connect(thread, SIGNAL(setBarSize(FileManipulatorThread*, unsigned int)),
437 this, SLOT(setBarSize(FileManipulatorThread*, unsigned int)));
438 connect(thread, SIGNAL(updateProgress(FileManipulatorThread*, int)),
439 this, SLOT(updateProgress(FileManipulatorThread*, int)));
440 connect(thread, SIGNAL(updateFileName(FileManipulatorThread*, QString)),
441 this, SLOT(updateMainText(FileManipulatorThread*, QString)));
442 connect(thread, SIGNAL(operationPaused(FileManipulatorThread*)),
443 this, SLOT(showPaused(FileManipulatorThread*)));
445 connect(thread->progressBar, SIGNAL(togglePauseOperation(FileManipulatorThread*)),
446 this, SLOT(togglePauseOperation(FileManipulatorThread*)));
447 connect(thread->progressBar, SIGNAL(abortOperation(FileManipulatorThread*)),
448 this, SLOT(abortOperation(FileManipulatorThread*)));
450 layout()->addWidget(thread->progressBar);
451 thread->start(QThread::LowestPriority);
455 FileManipulatorThread::FileManipulatorThread(const QFileInfoList files, QDir dest) :
456 progressBar(new ProgressBar(this)),
461 response(FileOperator::NONE),
462 overwriteAll(FileOperator::NONE),
471 memset(ignoreAll, false, sizeof(ignoreAll));
475 FileManipulatorThread::~FileManipulatorThread() {
476 if (!abort && progressBar->value() < progressBar->maximum()) {
477 std::cout << "WARNING: deleting a progressbar which's value " << progressBar->value() <<
478 " has not reached maximum of " << progressBar->maximum() << std::endl;
484 void FileManipulatorThread::setResponse(
485 const FileOperator::Response response,
486 const bool applyToAll,
491 this->response = response;
494 if (response == FileOperator::KEEP
495 || response == FileOperator::OVERWRITE
496 || response == FileOperator::NONE)
498 overwriteAll = response;
501 if (response == FileOperator::IGNORE) {
502 ignoreAll[err] = true;
506 if (response == FileOperator::ABORT) abort = true;
513 void FileManipulatorThread::processFiles(const QFileInfoList &files) {
514 for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
522 bool FileManipulatorThread::remove(QString &fileName, const bool doUpdates) {
523 return remove(QFileInfo(fileName), doUpdates);
527 bool FileManipulatorThread::remove(const QFileInfoList &files, const bool doUpdates) {
529 for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
530 if (!remove(*it, doUpdates)) res = false;
538 bool FileManipulatorThread::remove(const QFileInfo &file, const bool doUpdates) {
539 std::cout << "DELETING " << file.absoluteFilePath().toStdString() << std::endl;
541 QString path = file.absoluteFilePath();
543 if (removeExcludeFiles.contains(path)) {
544 if (doUpdates) updateProgress(1);
548 QFSFileEngine engine(path);
550 if (doUpdates) updateFile(path);
553 if (!remove(listDirFiles(path), doUpdates)) {
554 if (doUpdates) updateProgress(1);
558 if (!listDirFiles(path).size()) {
559 ERROR_PROMPT(!engine.rmdir(path, false), tr("Error deleting directory %1."), path)
562 ERROR_PROMPT(!engine.remove(), tr("Error deleting file %1."), path)
565 if (!abort && doUpdates) updateProgress(1);
568 if (abort || response == FileOperator::IGNORE) return false;
573 void FileManipulatorThread::copy(const QFileInfo &file) {
574 std::cout << "COPYING " << file.absoluteFilePath().toStdString()
575 << " to " << dest.absolutePath().toStdString() << std::endl;
577 QString path(file.absoluteFilePath());
578 QFSFileEngine engine(path);
579 QFileInfo newFile(dest.absolutePath() + "/" + file.fileName());
583 // hack to prevent asking about the same file if we already asked in the rename(...) function
584 if (overwriteAll == FileOperator::DONT_ASK_ONCE) {
585 overwriteAll = FileOperator::NONE;
587 OVERWRITE_PROMPT(file, newFile)
590 QString newPath(newFile.absoluteFilePath());
591 QFSFileEngine newEngine(newPath);
597 // save the overwrite response, because the response variable will get ovewritten in remove(...)
598 FileOperator::Response overwriteResponse = response;
600 if (newFile.exists() && !newFile.isDir()) {
601 // overwriting a file, so check for KEEP and handle it
602 if (response == FileOperator::KEEP) {
603 updateProgress(fileSizeMap[path]);
604 removeExcludeFiles.insert(path);
608 // if it should not be kept, remove it and return on failure
609 if(!remove(newPath)) {
610 updateProgress(fileSizeMap[path]);
613 // create new info since we deleted the file - is it needed?
614 newFile = QFileInfo(newPath);
616 // overwriting a directory - response KEEP means to keep the files inside,
617 // SKIP_DIR means to skip the dir completely
618 if (response == FileOperator::SKIP_DIR) {
619 updateProgress(fileSizeMap[path]);
620 removeExcludeFiles.insert(path);
625 if (!newFile.exists()) {
626 SPECIAL_COPY_ERROR_PROMPT(!engine.mkdir(newPath, false),
627 tr("Error creating directory %1."), newPath)
630 // we've done the job with the dir, so update progress and recurse into the dir
633 // change the dest for the recursion
634 QDir destBackup = dest;
637 // and set overwriteAll to the response we got a while ago
638 // because it applies to the files inside the dir
639 FileOperator::Response tmpResp = overwriteAll;
640 overwriteAll = overwriteResponse;
642 processFiles(listDirFiles(path));
644 overwriteAll = tmpResp;
646 ERROR_PROMPT(!newEngine.setPermissions(file.permissions()),
647 tr("Error setting permissions for directory %1."), newPath)
654 if (response == FileOperator::KEEP) {
655 updateProgress(fileSizeMap[path]);
656 removeExcludeFiles.insert(path);
660 SPECIAL_COPY_ERROR_PROMPT(checkSequentialFile(engine), tr("Cannot copy file %1."), path)
662 if (newFile.exists() && newFile.isDir()) {
663 SPECIAL_COPY_ERROR_PROMPT(!remove(newPath),
664 tr("Cannot replace directory %1 due to previous errors."), newPath)
667 SPECIAL_COPY_ERROR_PROMPT(!engine.open(QIODevice::ReadOnly), tr("Error reading file %1."), path)
669 bool ignore = false, newFileWritten = false;
670 while (!abort && !ignore) {
674 ERROR_PROMPT(!newEngine.open(QIODevice::WriteOnly | QIODevice::Truncate),
675 tr("Error writing file %1."), newPath)
677 if (abort || response == FileOperator::IGNORE) {
678 if (response == FileOperator::IGNORE) {
679 updateProgress(fileSizeMap[path]);
680 removeExcludeFiles.insert(path);
686 newFileWritten = true;
689 char block[BLOCK_SIZE];
691 while ((bytes = engine.read(block, sizeof(block))) > 0) {
692 if (bytes == -1 || bytes != newEngine.write(block, bytes)) {
694 SHOW_ERROR_PROMPT(tr("Error while reading from file %1."), path);
696 SHOW_ERROR_PROMPT(tr("Error while writing to file %1."), newPath);
700 if (response == FileOperator::IGNORE) {
701 updateProgress(fileSizeMap[path] - fileValue);
702 removeExcludeFiles.insert(path);
705 updateProgress(-fileValue);
726 if (abort || ignore) {
727 if (newFileWritten) {
731 ERROR_PROMPT(!newEngine.setPermissions(file.permissions()),
732 tr("Error setting permissions for file %1."), newPath)
738 unsigned int FileManipulatorThread::calculateFileSize(const QFileInfoList &files,
742 unsigned int res = 0;
744 for (QFileInfoList::const_iterator it = files.begin(); it != files.end(); ++it) {
745 unsigned int size = 0;
751 size += calculateFileSize(listDirFiles(it->absoluteFilePath()), count, addSize);
758 size += ceil(static_cast<float>(it->size()) / BLOCK_SIZE);
760 fileSizeMap[it->absoluteFilePath()] = size;
774 QFileInfoList FileManipulatorThread::listDirFiles(const QString &dirPath) {
776 return dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::System | QDir::Hidden);
780 void FileManipulatorThread::setBarSize(unsigned int size) {
782 emit setBarSize(this, size);
786 void FileManipulatorThread::updateProgress(int value) {
789 emit updateProgress(this, value);
793 void FileManipulatorThread::updateFile(const QString &name) {
795 emit updateFileName(this, FileOperator::shortenPath(name));
799 void FileManipulatorThread::waitOnCond() {
801 waitCond.wait(&mutex);
805 bool FileManipulatorThread::checkSequentialFile(const QFSFileEngine &engine) {
807 if (engine.isSequential()) {
808 if (!errno) errno = 255;
816 void FileManipulatorThread::wake() {
817 startTime += time(0) - waitTime;
822 void FileManipulatorThread::setText(int value) {
823 if (progressBar->value() + value > progressBar->maximum()) {
824 std::cout << "WARNING: exceeding progressbar maximum (" << progressBar->maximum()
825 << ") by " << value << std::endl;
828 time_t now = time(0);
829 if (lastTimeUpdate < now) {
830 lastTimeUpdate = now;
832 time_t elapsed = now - startTime;
833 time_t remaining = (time_t) ((float) elapsed / barValue * (barSize - barValue));
834 struct tm *ts = gmtime(&remaining);
836 if (remaining < 60) {
837 strftime(timeBuf, sizeof(timeBuf), "%Ss", ts);
838 } else if (remaining < 3600) {
839 strftime(timeBuf, sizeof(timeBuf), "%M:%S", ts);
841 strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S", ts);
846 progressBar->setFormat(QString("%p% ") + timeBuf);
847 progressBar->setValue(progressBar->value() + value);
851 DeleteThread::DeleteThread(const QFileInfoList &files) : FileManipulatorThread(files) {
852 barText = tr("deleting %1");
856 void DeleteThread::run() {
859 setBarSize(calculateFileSize(files, true));
869 void DeleteThread::perform(const QFileInfo &file) {
874 CopyThread::CopyThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {
875 barText = tr("copying %1");
879 void CopyThread::run() {
882 setBarSize(calculateFileSize(files, false, true));
892 void CopyThread::perform(const QFileInfo &file) {
897 MoveThread::MoveThread(const QFileInfoList &files, QDir &dest) : FileManipulatorThread(files, dest) {
898 barText = tr("moving %1");
902 void MoveThread::run() {
912 void MoveThread::rename(const QFileInfoList &files, const QDir &dest) {
913 setBarSize(barSize + files.size());
916 for (int i = 0; i < files.size(); ++i) {
917 QString path = files[i].absoluteFilePath();
918 QFSFileEngine engine(path);
919 QFileInfo newFile(dest.absolutePath() + "/" + files[i].fileName());
923 OVERWRITE_PROMPT(files[i], newFile)
925 // if we are owerwriting dir over a dir, we will get SKIP_DIR
926 // as a response from OVERWRITE_PROMT meaning we should skip it
927 // (KEEP would mean to keep the files inside)
928 if (files[i].isDir() && newFile.exists() && newFile.isDir()) {
929 if (response == FileOperator::SKIP_DIR) {
933 removeExcludeFiles.insert(path);
937 if (response == FileOperator::KEEP) {
941 removeExcludeFiles.insert(path);
946 QString newPath(newFile.absoluteFilePath());
947 QFSFileEngine newEngine(newPath);
951 while (!abort && !engine.rename(newPath)) {
952 // source and target are on different partitions
953 // this should happen on the first file, unless some are skipped by overwrite prompt
954 // we calculate the actual file sizes, because from now on copy & remove takes over
955 if (errno == EXDEV) {
956 overwriteAll = response;
957 // hack: we already checked the first file we are sending to processFiles(...)
958 // so we don't want to ask about this one again
959 if (overwriteAll == FileOperator::NONE) overwriteAll = FileOperator::DONT_ASK_ONCE;
961 QFileInfoList remainingFiles = files.mid(i);
963 setBarSize(barValue + calculateFileSize(remainingFiles, true, true));
965 processFiles(remainingFiles);
967 barText = tr("deleting %1");
969 remove(remainingFiles, true);
973 // the target is nonempty dir. lets call this recursively and rename the contents one by one
974 } else if (errno == ENOTEMPTY || errno == EEXIST) {
975 FileOperator::Response tmpResp = overwriteAll;
976 overwriteAll = response;
978 rename(listDirFiles(path), QDir(newPath));
982 overwriteAll = tmpResp;
987 // source and target are nonmatching types(file and dir)
988 // remove the target and let it loop once again
989 } else if (errno == ENOTDIR || errno == EISDIR) {
990 if (!remove(newPath)) break;
992 SHOW_ERROR_PROMPT(tr("Error moving %1."), path)
994 if (response == FileOperator::IGNORE) {
1010 void MoveThread::perform(const QFileInfo &file) {