aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-03-11 13:28:17 -0500
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-03-11 13:28:17 -0500
commit853a1f6259ea08f051e678276e95c4488d60efa4 (patch)
treec719b70157829280c8d92403a6bd986b3014ffd0 /src
parentad268d496f01512f3b67afeb8d6c358c17559c82 (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.cpp84
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();