summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-05-25 08:34:52 -0400
committerisanae <14251494+isanae@users.noreply.github.com>2019-05-25 08:34:52 -0400
commit76708b9694070bcaa5775a097ae73ffc163ca31b (patch)
treeb879155109cc5bc443855eee501a8807be19ab85 /src
parent54a743faea566d9040a1f972aef6d077ff68b198 (diff)
put explore and open functions in namespace shell
previewDataFile() was duplicated in both MainWindow and ModInfoDialog, moved to OrganizerCore added preview menu item to filetree better logging when shell operations fail
Diffstat (limited to 'src')
-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)