diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-03-11 13:28:17 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-03-11 13:28:17 -0500 |
| commit | 853a1f6259ea08f051e678276e95c4488d60efa4 (patch) | |
| tree | c719b70157829280c8d92403a6bd986b3014ffd0 /src | |
| parent | ad268d496f01512f3b67afeb8d6c358c17559c82 (diff) | |
Fix "Create Mod..." and "Move content to Mod..." overwrite context menu actions
The previous implementation used Windows SHFileOperation semantics that don't
work on Linux: literal wildcard in paths, QFile::copy on directories,
absolutePath() instead of absoluteFilePath(), and GetLastError() for errors.
Rewrite moveOverwriteContentsTo() to recursively iterate all files, compute
relative paths, and move each file individually with cross-filesystem fallback.
Empty directories in overwrite are cleaned up after the move.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/src/modlistviewactions.cpp | 84 |
1 files changed, 47 insertions, 37 deletions
diff --git a/src/src/modlistviewactions.cpp b/src/src/modlistviewactions.cpp index 051635f..040da79 100644 --- a/src/src/modlistviewactions.cpp +++ b/src/src/modlistviewactions.cpp @@ -1341,57 +1341,67 @@ void ModListViewActions::restoreBackup(const QModelIndex& index) const void ModListViewActions::moveOverwriteContentsTo(const QString& absolutePath) const
{
ModInfo::Ptr overwriteInfo = ModInfo::getOverwrite();
- bool successful = false;
- if (m_core.managedGame()->getModMappings().count() > 1 ||
- m_core.managedGame()->getModMappings().keys().first() != "") {
- QDirIterator iter(overwriteInfo->absolutePath(),
- QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
- while (iter.hasNext()) {
- auto entry = iter.nextFileInfo();
- if (entry.isDir() && m_core.managedGame()->getModMappings().keys().contains(
- entry.fileName(), Qt::CaseInsensitive)) {
- successful =
- shellCopy((QDir::toNativeSeparators(entry.absolutePath())),
- (QDir::toNativeSeparators(absolutePath)), false, m_parent);
- QDirIterator subDirIter(entry.absoluteFilePath(),
- QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
- while (subDirIter.hasNext()) {
- auto subDirEntry = subDirIter.nextFileInfo();
- if (subDirEntry.isDir()) {
- QDir(subDirEntry.absoluteFilePath()).removeRecursively();
- } else {
- QFile(subDirEntry.absoluteFilePath()).remove();
- }
- }
- } else {
- successful =
- shellMove((QDir::toNativeSeparators(iter.filePath())),
- (QDir::toNativeSeparators(absolutePath)), false, m_parent);
- }
- if (!successful)
+ const QString overwritePath = overwriteInfo->absolutePath();
+ const QDir overwriteDir(overwritePath);
+ const QDir destDir(absolutePath);
+
+ // Recursively move every file from overwrite into the destination mod,
+ // preserving the directory structure.
+ bool successful = true;
+ int movedCount = 0;
+
+ QDirIterator iter(overwritePath, QDir::Files | QDir::NoDotAndDotDot,
+ QDirIterator::Subdirectories);
+ while (iter.hasNext()) {
+ iter.next();
+ const QString relPath = overwriteDir.relativeFilePath(iter.filePath());
+ const QString destFile = destDir.filePath(relPath);
+
+ // Ensure destination subdirectory exists.
+ QDir().mkpath(QFileInfo(destFile).absolutePath());
+
+ // Remove existing file at destination (overwrite semantics).
+ if (QFile::exists(destFile)) {
+ QFile::remove(destFile);
+ }
+
+ if (!QFile::rename(iter.filePath(), destFile)) {
+ // Fallback: copy + delete (cross-filesystem).
+ if (!QFile::copy(iter.filePath(), destFile) || !QFile::remove(iter.filePath())) {
+ log::error("Failed to move {} -> {}", relPath, destFile);
+ successful = false;
break;
+ }
}
+ ++movedCount;
+ }
- } else {
- successful =
- shellMove((QDir::toNativeSeparators(overwriteInfo->absolutePath()) + QDir::separator() + "*"),
- (QDir::toNativeSeparators(absolutePath)), false, m_parent);
+ // Clean up empty directories left behind in overwrite.
+ if (movedCount > 0) {
+ QDirIterator dirIter(overwritePath, QDir::Dirs | QDir::NoDotAndDotDot,
+ QDirIterator::Subdirectories);
+ QStringList emptyDirs;
+ while (dirIter.hasNext()) {
+ emptyDirs.prepend(dirIter.next()); // Reverse order for leaf-first deletion.
+ }
+ for (const auto& dir : emptyDirs) {
+ QDir(dir).rmdir("."); // Only removes if empty.
+ }
}
- if (successful) {
+ if (successful && movedCount > 0) {
// Track all files now in the target mod so future VFS writes go
// back to this mod instead of creating new copies in Overwrite.
QDirIterator trackIter(absolutePath, QDir::Files | QDir::NoDotAndDotDot,
QDirIterator::Subdirectories);
while (trackIter.hasNext()) {
trackIter.next();
- QString relPath = QDir(absolutePath).relativeFilePath(trackIter.filePath());
+ QString relPath = destDir.relativeFilePath(trackIter.filePath());
m_core.trackOverwriteMove(relPath, absolutePath);
}
MessageDialog::showMessage(tr("Move successful."), m_parent);
- } else {
- const auto e = GetLastError();
- log::error("Move operation failed: {}", formatSystemMessage(e));
+ } else if (!successful) {
+ log::error("Move operation failed");
}
m_core.refresh();
|
