diff options
| -rw-r--r-- | src/downloadmanager.cpp | 8 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 98 | ||||
| -rw-r--r-- | src/modinfodialog.cpp | 133 | ||||
| -rw-r--r-- | src/modinfodialog.h | 12 | ||||
| -rw-r--r-- | src/organizercore.cpp | 228 | ||||
| -rw-r--r-- | src/organizercore.h | 15 | ||||
| -rw-r--r-- | src/overwriteinfodialog.cpp | 2 |
7 files changed, 311 insertions, 185 deletions
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 686092b5..1412df51 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -1037,7 +1037,7 @@ void DownloadManager::openFile(int index) return; } - ExploreFile(m_OutputDirectory); + shell::ExploreFile(m_OutputDirectory); return; } @@ -1051,18 +1051,18 @@ void DownloadManager::openInDownloadsFolder(int index) const auto path = getFilePath(index); if (QFile::exists(path)) { - ExploreFile(path); + shell::ExploreFile(path); return; } else { const auto unfinished = path + ".unfinished"; if (QFile::exists(unfinished)) { - ExploreFile(unfinished); + shell::ExploreFile(unfinished); return; } } - ExploreFile(m_OutputDirectory); + shell::ExploreFile(m_OutputDirectory); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ce6620c0..94cbe9b1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3241,12 +3241,12 @@ void MainWindow::openExplorer_clicked() if (selection->hasSelection() && selection->selectedRows().count() > 1) { for (QModelIndex idx : selection->selectedRows()) { ModInfo::Ptr info = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - ExploreFile(info->absolutePath()); + shell::ExploreFile(info->absolutePath()); } } else { ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow); - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } @@ -3261,14 +3261,14 @@ void MainWindow::openOriginExplorer_clicked() continue; } ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } else { QModelIndex idx = selection->currentIndex(); QString fileName = idx.data().toString(); ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } @@ -3283,7 +3283,7 @@ void MainWindow::openExplorer_activated() std::vector<ModInfo::EFlag> flags = modInfo->getFlags(); if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } @@ -3304,7 +3304,7 @@ void MainWindow::openExplorer_activated() std::vector<ModInfo::EFlag> flags = modInfo->getFlags(); if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - ExploreFile(modInfo->absolutePath()); + shell::ExploreFile(modInfo->absolutePath()); } } } @@ -4271,61 +4271,61 @@ void MainWindow::disableVisibleMods() void MainWindow::openInstanceFolder() { QString dataPath = qApp->property("dataPath").toString(); - ExploreFile(dataPath); + shell::ExploreFile(dataPath); } void MainWindow::openLogsFolder() { QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); - ExploreFile(logsPath); + shell::ExploreFile(logsPath); } void MainWindow::openInstallFolder() { - ExploreFile(qApp->applicationDirPath()); + shell::ExploreFile(qApp->applicationDirPath()); } void MainWindow::openPluginsFolder() { QString pluginsPath = QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); - ExploreFile(pluginsPath); + shell::ExploreFile(pluginsPath); } void MainWindow::openProfileFolder() { - ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); + shell::ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); } void MainWindow::openIniFolder() { if (m_OrganizerCore.currentProfile()->localSettingsEnabled()) { - ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); + shell::ExploreFile(m_OrganizerCore.currentProfile()->absolutePath()); } else { - ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); + shell::ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); } } void MainWindow::openDownloadsFolder() { - ExploreFile(m_OrganizerCore.settings().getDownloadDirectory()); + shell::ExploreFile(m_OrganizerCore.settings().getDownloadDirectory()); } void MainWindow::openModsFolder() { - ExploreFile(m_OrganizerCore.settings().getModDirectory()); + shell::ExploreFile(m_OrganizerCore.settings().getModDirectory()); } void MainWindow::openGameFolder() { - ExploreFile(m_OrganizerCore.managedGame()->gameDirectory()); + shell::ExploreFile(m_OrganizerCore.managedGame()->gameDirectory()); } void MainWindow::openMyGamesFolder() { - ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); + shell::ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory()); } @@ -5304,67 +5304,7 @@ void MainWindow::disableSelectedMods_clicked() void MainWindow::previewDataFile() { QString fileName = QDir::fromNativeSeparators(m_ContextItem->data(0, Qt::UserRole).toString()); - - // what we have is an absolute path to the file in its actual location (for the primary origin) - // what we want is the path relative to the virtual data directory - - // we need to look in the virtual directory for the file to make sure the info is up to date. - - // check if the file comes from the actual data folder instead of a mod - QDir gameDirectory = m_OrganizerCore.managedGame()->dataDirectory().absolutePath(); - QString relativePath = gameDirectory.relativeFilePath(fileName); - QDir dirRelativePath = gameDirectory.relativeFilePath(fileName); - // if the file is on a different drive the dirRelativePath will actually be an absolute path so we make sure that is not the case - if (!dirRelativePath.isAbsolute() && !relativePath.startsWith("..")) { - fileName = relativePath; - } - else { - // crude: we search for the next slash after the base mod directory to skip everything up to the data-relative directory - int offset = m_OrganizerCore.settings().getModDirectory().size() + 1; - offset = fileName.indexOf("/", offset); - fileName = fileName.mid(offset + 1); - } - - - - const FileEntry::Ptr file = m_OrganizerCore.directoryStructure()->searchFile(ToWString(fileName), nullptr); - - if (file.get() == nullptr) { - reportError(tr("file not found: %1").arg(qUtf8Printable(fileName))); - return; - } - - // set up preview dialog - PreviewDialog preview(fileName); - auto addFunc = [&] (int originId) { - FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId); - QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; - if (QFile::exists(filePath)) { - // it's very possible the file doesn't exist, because it's inside an archive. we don't support that - QWidget *wid = m_PluginContainer.previewGenerator().genPreview(filePath); - if (wid == nullptr) { - reportError(tr("failed to generate preview for %1").arg(filePath)); - } else { - preview.addVariant(ToQString(origin.getName()), wid); - } - } - }; - - addFunc(file->getOrigin()); - for (auto alt : file->getAlternatives()) { - addFunc(alt.first); - } - if (preview.numVariants() > 0) { - QSettings &settings = m_OrganizerCore.settings().directInterface(); - QString key = QString("geometry/%1").arg(preview.objectName()); - if (settings.contains(key)) { - preview.restoreGeometry(settings.value(key).toByteArray()); - } - preview.exec(); - settings.setValue(key, preview.saveGeometry()); - } else { - QMessageBox::information(this, tr("Sorry"), tr("Sorry, can't preview anything. This function currently does not support extracting from bsas.")); - } + m_OrganizerCore.previewFileWithAlternatives(this, fileName); } void MainWindow::openDataFile() @@ -5374,7 +5314,7 @@ void MainWindow::openDataFile() } QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString()); - m_OrganizerCore.executeFile(this, targetInfo); + m_OrganizerCore.executeFileVirtualized(this, targetInfo); } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 9bd36f7e..c3ef7c47 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -322,9 +322,9 @@ bool ExpanderWidget::opened() const ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directory, bool unmanaged, OrganizerCore *organizerCore, PluginContainer *pluginContainer, QWidget *parent) : TutorableDialog("ModInfoDialog", parent), ui(new Ui::ModInfoDialog), m_ModInfo(modInfo), m_ThumbnailMapper(this), m_RequestStarted(false), - m_NewFolderAction(nullptr), m_OpenAction(nullptr), m_RenameAction(nullptr), - m_DeleteAction(nullptr), m_HideAction(nullptr), m_UnhideAction(nullptr), - m_Directory(directory), m_Origin(nullptr), + m_NewFolderAction(nullptr), m_OpenAction(nullptr), m_PreviewAction(nullptr), + m_RenameAction(nullptr), m_DeleteAction(nullptr), m_HideAction(nullptr), + m_UnhideAction(nullptr), m_Directory(directory), m_Origin(nullptr), m_OrganizerCore(organizerCore), m_PluginContainer(pluginContainer) { ui->setupUi(this); @@ -483,16 +483,18 @@ void ModInfoDialog::initFiletree(ModInfo::Ptr modInfo) m_NewFolderAction = new QAction(tr("&New Folder"), ui->fileTree); m_OpenAction = new QAction(tr("&Open"), ui->fileTree); + m_PreviewAction = new QAction(tr("&Preview"), ui->fileTree); m_RenameAction = new QAction(tr("&Rename"), ui->fileTree); m_DeleteAction = new QAction(tr("&Delete"), ui->fileTree); m_HideAction = new QAction(tr("&Hide"), ui->fileTree); m_UnhideAction = new QAction(tr("&Unhide"), ui->fileTree); - QObject::connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered())); - QObject::connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered())); - QObject::connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered())); - QObject::connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered())); - QObject::connect(m_HideAction, SIGNAL(triggered()), this, SLOT(hideTriggered())); + connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered())); + connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered())); + connect(m_PreviewAction, SIGNAL(triggered()), this, SLOT(previewTriggered())); + connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered())); + connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered())); + connect(m_HideAction, SIGNAL(triggered()), this, SLOT(hideTriggered())); connect(m_UnhideAction, SIGNAL(triggered()), this, SLOT(unhideTriggered())); } @@ -1244,12 +1246,11 @@ bool ModInfoDialog::recursiveDelete(const QModelIndex &index) void ModInfoDialog::on_openInExplorerButton_clicked() { - ExploreFile(m_ModInfo->absolutePath()); + shell::ExploreFile(m_ModInfo->absolutePath()); } void ModInfoDialog::deleteFile(const QModelIndex &index) { - bool res = m_FileSystemModel->isDir(index) ? recursiveDelete(index) : m_FileSystemModel->remove(index); if (!res) { @@ -1406,21 +1407,29 @@ void ModInfoDialog::changeFiletreeVisibility(bool hide) } -void ModInfoDialog::openFile(const QModelIndex &index) +void ModInfoDialog::openTriggered() { - QString fileName = m_FileSystemModel->filePath(index); + if (m_FileSelection.size() == 1) { + const auto index = m_FileSelection.at(0); + if (!index.isValid()) { + return; + } - HINSTANCE res = ::ShellExecuteW(nullptr, L"open", ToWString(fileName).c_str(), nullptr, nullptr, SW_SHOW); - if ((unsigned long long)res <= 32) { - qCritical("failed to invoke %s: %d", qUtf8Printable(fileName), res); + QString fileName = m_FileSystemModel->filePath(index); + shell::OpenFile(fileName); } } - -void ModInfoDialog::openTriggered() +void ModInfoDialog::previewTriggered() { - foreach(QModelIndex idx, m_FileSelection) { - openFile(idx); + if (m_FileSelection.size() == 1) { + const auto index = m_FileSelection.at(0); + if (!index.isValid()) { + return; + } + + QString fileName = m_FileSystemModel->filePath(index); + m_OrganizerCore->previewFile(this, m_ModInfo->name(), fileName); } } @@ -1464,6 +1473,7 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) if (selectionModel->hasSelection()) { bool enableOpen = true; + bool enablePreview = true; bool enableRename = true; bool enableDelete = true; bool enableHide = true; @@ -1484,10 +1494,15 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) if (!hasFiles) { enableOpen = false; + enablePreview = false; } const QString fileName = m_FileSystemModel->fileName(m_FileSelection.at(0)); + if (!canPreviewFile(false, fileName)) { + enablePreview = false; + } + if (!canHideFile(false, fileName)) { enableHide = false; } @@ -1499,6 +1514,7 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) // this is a multiple selection, don't show open action so users don't open // a thousand files enableOpen = false; + enablePreview = false; enableRename = false; if (m_FileSelection.size() < max_scan_for_visibility) { @@ -1530,6 +1546,10 @@ void ModInfoDialog::on_fileTree_customContextMenuRequested(const QPoint &pos) menu.addAction(m_OpenAction); } + if (enablePreview) { + menu.addAction(m_PreviewAction); + } + if (enableRename) { menu.addAction(m_RenameAction); } @@ -1755,7 +1775,7 @@ void ModInfoDialog::openDataFile(const QTreeWidgetItem* item) } QFileInfo targetInfo(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->executeFile(this, targetInfo); + m_OrganizerCore->executeFileVirtualized(this, targetInfo); } void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) @@ -1765,63 +1785,17 @@ void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) } QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString()); + m_OrganizerCore->previewFileWithAlternatives(this, fileName); +} - // what we have is an absolute path to the file in its actual location (for the primary origin) - // what we want is the path relative to the virtual data directory - - // we need to look in the virtual directory for the file to make sure the info is up to date. - - // check if the file comes from the actual data folder instead of a mod - QDir gameDirectory = m_OrganizerCore->managedGame()->dataDirectory().absolutePath(); - QString relativePath = gameDirectory.relativeFilePath(fileName); - QDir direRelativePath = gameDirectory.relativeFilePath(fileName); - // if the file is on a different drive the dirRelativePath will actually be an absolute path so we make sure that is not the case - if (!direRelativePath.isAbsolute() && !relativePath.startsWith("..")) { - fileName = relativePath; - } - else { - // crude: we search for the next slash after the base mod directory to skip everything up to the data-relative directory - int offset = m_OrganizerCore->settings().getModDirectory().size() + 1; - offset = fileName.indexOf("/", offset); - fileName = fileName.mid(offset + 1); - } - - - - const FileEntry::Ptr file = m_OrganizerCore->directoryStructure()->searchFile(ToWString(fileName), nullptr); - - if (file.get() == nullptr) { - reportError(tr("file not found: %1").arg(qUtf8Printable(fileName))); - return; - } - - // set up preview dialog - PreviewDialog preview(fileName); - auto addFunc = [&](int originId) { - FilesOrigin &origin = m_OrganizerCore->directoryStructure()->getOriginByID(originId); - QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; - if (QFile::exists(filePath)) { - // it's very possible the file doesn't exist, because it's inside an archive. we don't support that - QWidget *wid = m_PluginContainer->previewGenerator().genPreview(filePath); - if (wid == nullptr) { - reportError(tr("failed to generate preview for %1").arg(filePath)); - } - else { - preview.addVariant(ToQString(origin.getName()), wid); - } - } - }; +bool ModInfoDialog::canPreviewFile(bool isArchive, const QString& filename) const +{ + if (isArchive) { + return false; + } - addFunc(file->getOrigin()); - for (auto alt : file->getAlternatives()) { - addFunc(alt.first); - } - if (preview.numVariants() > 0) { - preview.exec(); - } - else { - QMessageBox::information(this, tr("Sorry"), tr("Sorry, can't preview anything. This function currently does not support extracting from bsas.")); - } + const auto ext = QFileInfo(filename).suffix(); + return m_PluginContainer->previewGenerator().previewSupported(ext); } bool ModInfoDialog::canHideFile(bool isArchive, const QString& filename) const @@ -1866,12 +1840,9 @@ bool ModInfoDialog::canUnhideConflictItem(const QTreeWidgetItem* item) const bool ModInfoDialog::canPreviewConflictItem(const QTreeWidgetItem* item) const { - const QString fileName = item->data(0, Qt::UserRole).toString(); - if (!m_PluginContainer->previewGenerator().previewSupported(QFileInfo(fileName).suffix())) { - return false; - } - - return true; + return canPreviewFile( + item->data(1, Qt::UserRole + 2).toBool(), + item->data(0, Qt::UserRole).toString()); } void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &pos) diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 6bf30a52..c0730afa 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -313,7 +313,6 @@ private: QString getFileCategory(int categoryID);
bool recursiveDelete(const QModelIndex &index);
void deleteFile(const QModelIndex &index);
- void openFile(const QModelIndex &index);
void saveIniTweaks();
void saveCategories(QTreeWidgetItem *currentNode);
void saveCurrentTextFile();
@@ -348,10 +347,11 @@ private slots: void delete_activated();
- void deleteTriggered();
- void renameTriggered();
- void openTriggered();
void createDirectoryTriggered();
+ void openTriggered();
+ void previewTriggered();
+ void renameTriggered();
+ void deleteTriggered();
void hideTriggered();
void unhideTriggered();
@@ -416,6 +416,7 @@ private: QAction *m_NewFolderAction;
QAction *m_OpenAction;
+ QAction *m_PreviewAction;
QAction *m_RenameAction;
QAction *m_DeleteAction;
QAction *m_HideAction;
@@ -439,11 +440,12 @@ private: bool canUnhideConflictItem(const QTreeWidgetItem* item) const;
bool canPreviewConflictItem(const QTreeWidgetItem* item) const;
- void previewDataFile(const QTreeWidgetItem* item);
void openDataFile(const QTreeWidgetItem* item);
+ void previewDataFile(const QTreeWidgetItem* item);
void changeConflictFilesVisibility(bool hide);
void changeFiletreeVisibility(bool hide);
+ bool canPreviewFile(bool isArchive, const QString& filename) const;
bool canHideFile(bool isArchive, const QString& filename) const;
bool canUnhideFile(bool isArchive, const QString& filename) const;
};
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d228dfe1..3a6b810e 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -35,6 +35,7 @@ #include "instancemanager.h" #include <scriptextender.h> #include "helper.h" +#include "previewdialog.h" #include <QApplication> #include <QCoreApplication> @@ -331,16 +332,103 @@ bool GetFileExecutionContext( } -bool ExploreDirectory(const QFileInfo& info) +const char* ShellExecuteError(int i) { - const auto path = QDir::toNativeSeparators(info.absoluteFilePath()); - const auto ws_path = path.toStdWString(); + switch (i) { + case 0: + return "The operating system is out of memory or resources"; + + case ERROR_FILE_NOT_FOUND: + return "The specified file was not found"; + + case ERROR_PATH_NOT_FOUND: + return "The specified path was not found"; + + case ERROR_BAD_FORMAT: + return "The .exe file is invalid (non-Win32 .exe or error in .exe image)"; + + case SE_ERR_ACCESSDENIED: + return "The operating system denied access to the specified file"; + + case SE_ERR_ASSOCINCOMPLETE: + return "The file name association is incomplete or invalid"; + + case SE_ERR_DDEBUSY: + return "The DDE transaction could not be completed because other DDE " + "transactions were being processed"; + + case SE_ERR_DDEFAIL: + return "The DDE transaction failed"; + + case SE_ERR_DDETIMEOUT: + return "The DDE transaction could not be completed because the request " + "timed out"; + + case SE_ERR_DLLNOTFOUND: + return "The specified DLL was not found"; + + case SE_ERR_NOASSOC: + return "There is no application associated with the given file name " + "extension"; + + case SE_ERR_OOM: + return "There was not enough memory to complete the operation"; + + case SE_ERR_SHARE: + return "A sharing violation occurred"; + + default: + return "Unknown error"; + } +} + +void LogShellFailure( + const wchar_t* operation, const wchar_t* file, const wchar_t* params, + HINSTANCE h) +{ + const auto code = static_cast<int>(reinterpret_cast<std::size_t>(h)); + + QString s = "failed to invoke"; + + if (operation) { + s += " " + QString::fromWCharArray(operation); + } + + if (file) { + s += " " + QString::fromWCharArray(file); + } + if (params) { + s += " " + QString::fromWCharArray(params); + } + + qCritical( + "failed to invoke %s: %s (error %d)", + s, ShellExecuteError(code), code); +} + +bool ShellExecuteWrapper( + const wchar_t* operation, const wchar_t* file, const wchar_t* params) +{ const auto h = ::ShellExecuteW( - nullptr, L"explore", ws_path.c_str(), nullptr, nullptr, SW_SHOWNORMAL); + 0, operation, file, params, nullptr, SW_SHOWNORMAL); // anything <= 32 is not an actual HINSTANCE and signals failure - return (h > reinterpret_cast<HINSTANCE>(32)); + if (h <= reinterpret_cast<HINSTANCE>(32)) + { + LogShellFailure(operation, file, params, h); + return false; + } + + return true; +} + +bool ExploreDirectory(const QFileInfo& info) +{ + const auto path = QDir::toNativeSeparators(info.absoluteFilePath()); + const auto ws_path = path.toStdWString(); + + return ShellExecuteWrapper(L"explore", ws_path.c_str(), nullptr); } bool ExploreFileInDirectory(const QFileInfo& info) @@ -349,14 +437,13 @@ bool ExploreFileInDirectory(const QFileInfo& info) const auto params = "/select,\"" + path + "\""; const auto ws_params = params.toStdWString(); - const auto h = ::ShellExecuteW( - nullptr, nullptr, L"explorer", ws_params.c_str(), nullptr, SW_SHOWNORMAL); - - // anything <= 32 is not an actual HINSTANCE and signals failure - return (h > reinterpret_cast<HINSTANCE>(32)); + return ShellExecuteWrapper(nullptr, L"explorer", ws_params.c_str()); } +namespace shell +{ + bool ExploreFile(const QFileInfo& info) { if (info.isFile()) { @@ -385,6 +472,14 @@ bool ExploreFile(const QDir& dir) return ExploreFile(QFileInfo(dir.absolutePath())); } +bool OpenFile(const QString& path) +{ + const auto ws_path = path.toStdWString(); + return ShellExecuteWrapper(L"open", ws_path.c_str(), nullptr); +} + +} // namespace shell + OrganizerCore::OrganizerCore(const QSettings &initSettings) : m_UserInterface(nullptr) @@ -1339,7 +1434,8 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const return res; } -bool OrganizerCore::executeFile(QWidget* parent, const QFileInfo& targetInfo) +bool OrganizerCore::executeFileVirtualized( + QWidget* parent, const QFileInfo& targetInfo) { QFileInfo binaryInfo; QString arguments; @@ -1372,6 +1468,116 @@ bool OrganizerCore::executeFile(QWidget* parent, const QFileInfo& targetInfo) return false; } +bool OrganizerCore::previewFileWithAlternatives( + QWidget* parent, QString fileName) +{ + // what we have is an absolute path to the file in its actual location (for the primary origin) + // what we want is the path relative to the virtual data directory + + // we need to look in the virtual directory for the file to make sure the info is up to date. + + // check if the file comes from the actual data folder instead of a mod + QDir gameDirectory = managedGame()->dataDirectory().absolutePath(); + QString relativePath = gameDirectory.relativeFilePath(fileName); + QDir dirRelativePath = gameDirectory.relativeFilePath(fileName); + + // if the file is on a different drive the dirRelativePath will actually be an + // absolute path so we make sure that is not the case + if (!dirRelativePath.isAbsolute() && !relativePath.startsWith("..")) { + fileName = relativePath; + } + else { + // crude: we search for the next slash after the base mod directory to skip + // everything up to the data-relative directory + int offset = settings().getModDirectory().size() + 1; + offset = fileName.indexOf("/", offset); + fileName = fileName.mid(offset + 1); + } + + + + const FileEntry::Ptr file = directoryStructure()->searchFile(ToWString(fileName), nullptr); + + if (file.get() == nullptr) { + reportError(tr("file not found: %1").arg(qUtf8Printable(fileName))); + return false; + } + + // set up preview dialog + PreviewDialog preview(fileName); + auto addFunc = [&](int originId) { + FilesOrigin &origin = directoryStructure()->getOriginByID(originId); + QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; + if (QFile::exists(filePath)) { + // it's very possible the file doesn't exist, because it's inside an archive. we don't support that + QWidget *wid = m_PluginContainer->previewGenerator().genPreview(filePath); + if (wid == nullptr) { + reportError(tr("failed to generate preview for %1").arg(filePath)); + } + else { + preview.addVariant(ToQString(origin.getName()), wid); + } + } + }; + + addFunc(file->getOrigin()); + for (auto alt : file->getAlternatives()) { + addFunc(alt.first); + } + + if (preview.numVariants() > 0) { + QSettings &s = settings().directInterface(); + QString key = QString("geometry/%1").arg(preview.objectName()); + if (s.contains(key)) { + preview.restoreGeometry(s.value(key).toByteArray()); + } + + preview.exec(); + + s.setValue(key, preview.saveGeometry()); + + return true; + } + else { + QMessageBox::information( + parent, tr("Sorry"), + tr("Sorry, can't preview anything. This function currently does not support extracting from bsas.")); + + return false; + } +} + +bool OrganizerCore::previewFile( + QWidget* parent, const QString& originName, const QString& path) +{ + if (!QFile::exists(path)) { + reportError(tr("File '%1' not found.").arg(path)); + return false; + } + + PreviewDialog preview(path); + + QWidget *wid = m_PluginContainer->previewGenerator().genPreview(path); + if (wid == nullptr) { + reportError(tr("Failed to generate preview for %1").arg(path)); + return false; + } + + preview.addVariant(originName, wid); + + QSettings &s = settings().directInterface(); + QString key = QString("geometry/%1").arg(preview.objectName()); + if (s.contains(key)) { + preview.restoreGeometry(s.value(key).toByteArray()); + } + + preview.exec(); + + s.setValue(key, preview.saveGeometry()); + + return true; +} + void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory, diff --git a/src/organizercore.h b/src/organizercore.h index 3f773277..41f0fd46 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -67,9 +67,14 @@ bool GetFileExecutionContext( QWidget* parent, const QFileInfo &targetInfo,
QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type);
-bool ExploreFile(const QFileInfo& info);
-bool ExploreFile(const QString& path);
-bool ExploreFile(const QDir& dir);
+namespace shell
+{
+ bool ExploreFile(const QFileInfo& info);
+ bool ExploreFile(const QString& path);
+ bool ExploreFile(const QDir& dir);
+
+ bool OpenFile(const QString& path);
+}
class OrganizerCore : public QObject, public MOBase::IPluginDiagnose
@@ -156,7 +161,9 @@ public: void doAfterLogin(const std::function<void()> &function) { m_PostLoginTasks.append(function); }
- bool executeFile(QWidget* parent, const QFileInfo& targetInfo);
+ bool executeFileVirtualized(QWidget* parent, const QFileInfo& targetInfo);
+ bool previewFileWithAlternatives(QWidget* parent, QString filename);
+ bool previewFile(QWidget* parent, const QString& originName, const QString& path);
void spawnBinary(const QFileInfo &binary, const QString &arguments = "",
const QDir ¤tDirectory = QDir(),
diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index e9d7ce06..d6764852 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -264,7 +264,7 @@ void OverwriteInfoDialog::createDirectoryTriggered() void OverwriteInfoDialog::on_explorerButton_clicked()
{
- ExploreFile(m_ModInfo->absolutePath());
+ shell::ExploreFile(m_ModInfo->absolutePath());
}
void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint &pos)
|
