summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/downloadmanager.cpp8
-rw-r--r--src/mainwindow.cpp98
-rw-r--r--src/modinfodialog.cpp133
-rw-r--r--src/modinfodialog.h12
-rw-r--r--src/organizercore.cpp228
-rw-r--r--src/organizercore.h15
-rw-r--r--src/overwriteinfodialog.cpp2
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 &currentDirectory,
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 &currentDirectory = 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)