summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAl <gabriel.cortesi@outlook.com>2019-05-26 12:24:02 +0200
committerGitHub <noreply@github.com>2019-05-26 12:24:02 +0200
commit2caa688e5581849441b1c96e4a2d357e9241f74a (patch)
treec99b83f84f4be692663be4256e9ec955f4258e7e /src
parent2d58ad346c9e8840d3864080d62999e686962a76 (diff)
parent21185182c6551d053cccdcf087e0c219a3785cf8 (diff)
Merge pull request #731 from isanae/filetree-dds-preview-630
Add preview to filetree, some refactoring
Diffstat (limited to 'src')
-rw-r--r--src/downloadmanager.cpp29
-rw-r--r--src/mainwindow.cpp219
-rw-r--r--src/mainwindow.h1
-rw-r--r--src/modinfodialog.cpp219
-rw-r--r--src/modinfodialog.h19
-rw-r--r--src/motddialog.cpp3
-rw-r--r--src/organizercore.cpp371
-rw-r--r--src/organizercore.h28
-rw-r--r--src/overwriteinfodialog.cpp10
-rw-r--r--src/problemsdialog.cpp3
-rw-r--r--src/selfupdater.cpp19
-rw-r--r--src/settings.cpp23
12 files changed, 554 insertions, 390 deletions
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index d4a6c37f..648b102a 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -1041,14 +1041,14 @@ void DownloadManager::openFile(int index)
reportError(tr("OpenFile: invalid download index %1").arg(index));
return;
}
+
QDir path = QDir(m_OutputDirectory);
if (path.exists(getFileName(index))) {
-
- ::ShellExecuteW(nullptr, L"open", ToWString(QDir::toNativeSeparators(getFilePath(index))).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::OpenFile(getFilePath(index));
return;
}
- ::ShellExecuteW(nullptr, L"explore", ToWString(QDir::toNativeSeparators(m_OutputDirectory)).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_OutputDirectory);
return;
}
@@ -1058,23 +1058,22 @@ void DownloadManager::openInDownloadsFolder(int index)
reportError(tr("OpenFileInDownloadsFolder: invalid download index %1").arg(index));
return;
}
- QString params = "/select,\"";
- QDir path = QDir(m_OutputDirectory);
- if (path.exists(getFileName(index))) {
- params = params + QDir::toNativeSeparators(getFilePath(index)) + "\"";
- ::ShellExecuteW(nullptr, nullptr, L"explorer", ToWString(params).c_str(), nullptr, SW_SHOWNORMAL);
- return;
- }
- else if (path.exists(getFileName(index) + ".unfinished")) {
- params = params + QDir::toNativeSeparators(getFilePath(index)+".unfinished") + "\"";
+ const auto path = getFilePath(index);
- ::ShellExecuteW(nullptr, nullptr, L"explorer", ToWString(params).c_str(), nullptr, SW_SHOWNORMAL);
+ if (QFile::exists(path)) {
+ shell::ExploreFile(path);
return;
}
+ else {
+ const auto unfinished = path + ".unfinished";
+ if (QFile::exists(unfinished)) {
+ shell::ExploreFile(unfinished);
+ return;
+ }
+ }
- ::ShellExecuteW(nullptr, L"explore", ToWString(QDir::toNativeSeparators(m_OutputDirectory)).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
- return;
+ shell::ExploreFile(m_OutputDirectory);
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 1b95ea0b..810caa01 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());
- ::ShellExecuteW(nullptr, L"explore", ToWString(info->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(info->absolutePath());
}
}
else {
ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
- ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(modInfo->absolutePath());
}
}
@@ -3261,18 +3261,14 @@ void MainWindow::openOriginExplorer_clicked()
continue;
}
ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
- std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
-
- ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ 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)));
- std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
-
- ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(modInfo->absolutePath());
}
}
@@ -3287,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())) {
- ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(modInfo->absolutePath());
}
}
@@ -3308,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())) {
- ::ShellExecuteW(nullptr, L"explore", ToWString(modInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(modInfo->absolutePath());
}
}
}
@@ -4275,64 +4271,61 @@ void MainWindow::disableVisibleMods()
void MainWindow::openInstanceFolder()
{
QString dataPath = qApp->property("dataPath").toString();
- ::ShellExecuteW(nullptr, L"explore", ToWString(dataPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
-
- //opens BaseDirectory instead
- //::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getBaseDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(dataPath);
}
void MainWindow::openLogsFolder()
{
QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath());
- ::ShellExecuteW(nullptr, L"explore", ToWString(logsPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(logsPath);
}
void MainWindow::openInstallFolder()
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(qApp->applicationDirPath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(qApp->applicationDirPath());
}
void MainWindow::openPluginsFolder()
{
QString pluginsPath = QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath());
- ::ShellExecuteW(nullptr, L"explore", ToWString(pluginsPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(pluginsPath);
}
void MainWindow::openProfileFolder()
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.currentProfile()->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_OrganizerCore.currentProfile()->absolutePath());
}
void MainWindow::openIniFolder()
{
if (m_OrganizerCore.currentProfile()->localSettingsEnabled())
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.currentProfile()->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_OrganizerCore.currentProfile()->absolutePath());
}
else {
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->documentsDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory());
}
}
void MainWindow::openDownloadsFolder()
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getDownloadDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_OrganizerCore.settings().getDownloadDirectory());
}
void MainWindow::openModsFolder()
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getModDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_OrganizerCore.settings().getModDirectory());
}
void MainWindow::openGameFolder()
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->gameDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_OrganizerCore.managedGame()->gameDirectory());
}
void MainWindow::openMyGamesFolder()
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->documentsDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_OrganizerCore.managedGame()->documentsDirectory());
}
@@ -5153,73 +5146,30 @@ void MainWindow::writeDataToFile()
}
}
-
-int MainWindow::getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments)
+void MainWindow::addAsExecutable()
{
- QString extension = targetInfo.suffix();
- if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) ||
- (extension.compare("com", Qt::CaseInsensitive) == 0) ||
- (extension.compare("bat", Qt::CaseInsensitive) == 0)) {
- binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe");
- arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
- return 1;
- } else if (extension.compare("exe", Qt::CaseInsensitive) == 0) {
- binaryInfo = targetInfo;
- return 1;
- } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) {
- // types that need to be injected into
- std::wstring targetPathW = ToWString(targetInfo.absoluteFilePath());
- QString binaryPath;
-
- { // try to find java automatically
- WCHAR buffer[MAX_PATH];
- if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) {
- DWORD binaryType = 0UL;
- if (!::GetBinaryTypeW(buffer, &binaryType)) {
- qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError());
- } else if (binaryType == SCS_32BIT_BINARY) {
- binaryPath = ToQString(buffer);
- }
- }
- }
- if (binaryPath.isEmpty() && (extension == "jar")) {
- // second attempt: look to the registry
- QSettings javaReg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat);
- if (javaReg.contains("CurrentVersion")) {
- QString currentVersion = javaReg.value("CurrentVersion").toString();
- binaryPath = javaReg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe");
- }
- }
- if (binaryPath.isEmpty()) {
- binaryPath = QFileDialog::getOpenFileName(this, tr("Select binary"), QString(), tr("Binary") + " (*.exe)");
- }
- if (binaryPath.isEmpty()) {
- return 0;
- }
- binaryInfo = QFileInfo(binaryPath);
- if (extension == "jar") {
- arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
- } else {
- arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
- }
- return 1;
- } else {
- return 2;
+ if (m_ContextItem == nullptr) {
+ return;
}
-}
+ using FileExecutionTypes = OrganizerCore::FileExecutionTypes;
-void MainWindow::addAsExecutable()
-{
- if (m_ContextItem != nullptr) {
- QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString());
- QFileInfo binaryInfo;
- QString arguments;
- switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) {
- case 1: {
+ QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString());
+ QFileInfo binaryInfo;
+ QString arguments;
+ FileExecutionTypes type;
+
+ if (!OrganizerCore::getFileExecutionContext(this, targetInfo, binaryInfo, arguments, type)) {
+ return;
+ }
+
+ switch (type)
+ {
+ case FileExecutionTypes::Executable: {
QString name = QInputDialog::getText(this, tr("Enter Name"),
tr("Please enter a name for the executable"), QLineEdit::Normal,
targetInfo.baseName());
+
if (!name.isEmpty()) {
//Note: If this already exists, you'll lose custom settings
m_OrganizerCore.executablesList()->addExecutable(name,
@@ -5230,14 +5180,15 @@ void MainWindow::addAsExecutable()
Executable::CustomExecutable);
refreshExecutablesList();
}
- } break;
- case 2: {
+
+ break;
+ }
+
+ case FileExecutionTypes::Other: // fall-through
+ default: {
QMessageBox::information(this, tr("Not an executable"), tr("This is not a recognized executable."));
- } break;
- default: {
- // nop
- } break;
- }
+ break;
+ }
}
}
@@ -5355,91 +5306,17 @@ 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()
{
- if (m_ContextItem != nullptr) {
- QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString());
- QFileInfo binaryInfo;
- QString arguments;
- switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) {
- case 1: {
- m_OrganizerCore.spawnBinaryDirect(
- binaryInfo, arguments, m_OrganizerCore.currentProfile()->name(),
- targetInfo.absolutePath(), "", "");
- } break;
- case 2: {
- ::ShellExecuteW(nullptr, L"open",
- ToWString(targetInfo.absoluteFilePath()).c_str(),
- nullptr, nullptr, SW_SHOWNORMAL);
- } break;
- default: {
- // nop
- } break;
- }
+ if (m_ContextItem == nullptr) {
+ return;
}
+
+ QFileInfo targetInfo(m_ContextItem->data(0, Qt::UserRole).toString());
+ m_OrganizerCore.executeFileVirtualized(this, targetInfo);
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 727dd165..b4ad0bdb 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -260,7 +260,6 @@ private:
size_t checkForProblems();
- int getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments);
QTreeWidgetItem *addFilterItem(QTreeWidgetItem *root, const QString &name, int categoryID, ModListSortProxy::FilterType type);
void addContentFilters();
void addCategoryFilters(QTreeWidgetItem *root, const std::set<int> &categoriesUsed, int targetID);
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index 1304b27a..19a03ea7 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -322,8 +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_DeleteAction(nullptr), m_RenameAction(nullptr), m_OpenAction(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);
@@ -480,17 +481,20 @@ void ModInfoDialog::initFiletree(ModInfo::Ptr modInfo)
ui->fileTree->setRootIndex(m_FileSystemModel->index(m_RootPath));
ui->fileTree->setColumnWidth(0, 300);
- m_DeleteAction = new QAction(tr("&Delete"), ui->fileTree);
+ 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);
- m_OpenAction = new QAction(tr("&Open"), ui->fileTree);
- m_NewFolderAction = new QAction(tr("&New Folder"), ui->fileTree);
- QObject::connect(m_DeleteAction, SIGNAL(triggered()), this, SLOT(deleteTriggered()));
- QObject::connect(m_RenameAction, SIGNAL(triggered()), this, SLOT(renameTriggered()));
- QObject::connect(m_OpenAction, SIGNAL(triggered()), this, SLOT(openTriggered()));
- QObject::connect(m_NewFolderAction, SIGNAL(triggered()), this, SLOT(createDirectoryTriggered()));
- 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()));
}
@@ -1071,10 +1075,9 @@ void ModInfoDialog::linkClicked(const QUrl &url)
//Ideally we'd ask the mod for the game and the web service then pass the game
//and URL to the web service
if (NexusInterface::instance(m_PluginContainer)->isURLGameRelated(url)) {
-
emit linkActivated(url.toString());
} else {
- ::ShellExecuteW(nullptr, L"open", ToWString(url.toString()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::OpenLink(url);
}
}
@@ -1242,12 +1245,11 @@ bool ModInfoDialog::recursiveDelete(const QModelIndex &index)
void ModInfoDialog::on_openInExplorerButton_clicked()
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_ModInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ 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) {
@@ -1404,21 +1406,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);
}
}
@@ -1462,6 +1472,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;
@@ -1482,10 +1493,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;
}
@@ -1497,6 +1513,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) {
@@ -1528,6 +1545,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);
}
@@ -1696,65 +1717,6 @@ void ModInfoDialog::unhideConflictFiles()
changeConflictFilesVisibility(false);
}
-int ModInfoDialog::getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments)
-{
- QString extension = targetInfo.suffix();
- if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) ||
- (extension.compare("com", Qt::CaseInsensitive) == 0) ||
- (extension.compare("bat", Qt::CaseInsensitive) == 0)) {
- binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe");
- arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
- return 1;
- }
- else if (extension.compare("exe", Qt::CaseInsensitive) == 0) {
- binaryInfo = targetInfo;
- return 1;
- }
- else if (extension.compare("jar", Qt::CaseInsensitive) == 0) {
- // types that need to be injected into
- std::wstring targetPathW = ToWString(targetInfo.absoluteFilePath());
- QString binaryPath;
-
- { // try to find java automatically
- WCHAR buffer[MAX_PATH];
- if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) {
- DWORD binaryType = 0UL;
- if (!::GetBinaryTypeW(buffer, &binaryType)) {
- qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError());
- }
- else if (binaryType == SCS_32BIT_BINARY) {
- binaryPath = ToQString(buffer);
- }
- }
- }
- if (binaryPath.isEmpty() && (extension == "jar")) {
- // second attempt: look to the registry
- QSettings javaReg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat);
- if (javaReg.contains("CurrentVersion")) {
- QString currentVersion = javaReg.value("CurrentVersion").toString();
- binaryPath = javaReg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe");
- }
- }
- if (binaryPath.isEmpty()) {
- binaryPath = QFileDialog::getOpenFileName(this, tr("Select binary"), QString(), tr("Binary") + " (*.exe)");
- }
- if (binaryPath.isEmpty()) {
- return 0;
- }
- binaryInfo = QFileInfo(binaryPath);
- if (extension == "jar") {
- arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
- }
- else {
- arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
- }
- return 1;
- }
- else {
- return 2;
- }
-}
-
void ModInfoDialog::previewOverwriteDataFile()
{
// the menu item is only shown for a single selection, but check just in case
@@ -1812,23 +1774,7 @@ void ModInfoDialog::openDataFile(const QTreeWidgetItem* item)
}
QFileInfo targetInfo(item->data(0, Qt::UserRole).toString());
- QFileInfo binaryInfo;
- QString arguments;
- switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) {
- case 1: {
- m_OrganizerCore->spawnBinaryDirect(
- binaryInfo, arguments, m_OrganizerCore->currentProfile()->name(),
- targetInfo.absolutePath(), "", "");
- } break;
- case 2: {
- ::ShellExecuteW(nullptr, L"open",
- ToWString(targetInfo.absoluteFilePath()).c_str(),
- nullptr, nullptr, SW_SHOWNORMAL);
- } break;
- default: {
- // nop
- } break;
- }
+ m_OrganizerCore->executeFileVirtualized(this, targetInfo);
}
void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item)
@@ -1838,63 +1784,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
@@ -1939,12 +1839,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)
@@ -2016,7 +1913,7 @@ void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &po
// note that it is possible for hidden files to appear if they override other
// hidden files from another mod
if (enableUnhide) {
- menu.addAction(tr("Un-Hide"), this, SLOT(unhideConflictFiles()));
+ menu.addAction(tr("Unhide"), this, SLOT(unhideConflictFiles()));
}
if (enableOpen) {
diff --git a/src/modinfodialog.h b/src/modinfodialog.h
index dc04deb3..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();
@@ -335,7 +334,6 @@ private slots:
void unhideConflictFiles();
void previewOverwriteDataFile();
void openOverwriteDataFile();
- int getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments);
void previewOverwrittenDataFile();
void openOverwrittenDataFile();
@@ -349,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();
@@ -415,10 +414,11 @@ private:
std::set<int> m_RequestIDs;
bool m_RequestStarted;
- QAction *m_DeleteAction;
- QAction *m_RenameAction;
- QAction *m_OpenAction;
QAction *m_NewFolderAction;
+ QAction *m_OpenAction;
+ QAction *m_PreviewAction;
+ QAction *m_RenameAction;
+ QAction *m_DeleteAction;
QAction *m_HideAction;
QAction *m_UnhideAction;
@@ -440,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/motddialog.cpp b/src/motddialog.cpp
index 96d88542..9be41d96 100644
--- a/src/motddialog.cpp
+++ b/src/motddialog.cpp
@@ -21,6 +21,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "bbcode.h"
#include "utility.h"
#include "ui_motddialog.h"
+#include "organizercore.h"
#include <Shlwapi.h>
MotDDialog::MotDDialog(const QString &message, QWidget *parent)
@@ -43,5 +44,5 @@ void MotDDialog::on_okButton_clicked()
void MotDDialog::linkClicked(const QUrl &url)
{
- ::ShellExecuteW(nullptr, L"open", MOBase::ToWString(url.toString()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::OpenLink(url);
}
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 8212d248..d3de3e01 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>
@@ -267,6 +268,170 @@ bool checkService()
return serviceRunning;
}
+
+const char* ShellExecuteError(int i)
+{
+ 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(
+ 0, operation, file, params, nullptr, SW_SHOWNORMAL);
+
+ // anything <= 32 is not an actual HINSTANCE and signals failure
+ 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)
+{
+ const auto path = QDir::toNativeSeparators(info.absoluteFilePath());
+ const auto params = "/select,\"" + path + "\"";
+ const auto ws_params = params.toStdWString();
+
+ return ShellExecuteWrapper(nullptr, L"explorer", ws_params.c_str());
+}
+
+
+namespace shell
+{
+
+bool ExploreFile(const QFileInfo& info)
+{
+ if (info.isFile()) {
+ return ExploreFileInDirectory(info);
+ } else if (info.isDir()) {
+ return ExploreDirectory(info);
+ } else {
+ // try the parent directory
+ const auto parent = info.dir();
+
+ if (parent.exists()) {
+ return ExploreDirectory(parent.absolutePath());
+ }
+ }
+
+ return false;
+}
+
+bool ExploreFile(const QString& path)
+{
+ return ExploreFile(QFileInfo(path));
+}
+
+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);
+}
+
+bool OpenLink(const QUrl& url)
+{
+ const auto ws_url = url.toString().toStdWString();
+ return ShellExecuteWrapper(L"open", ws_url.c_str(), nullptr);
+}
+
+bool Execute(const QString& program, const QString& params)
+{
+ const auto program_ws = program.toStdWString();
+ const auto params_ws = params.toStdWString();
+
+ return ShellExecuteWrapper(L"open", program_ws.c_str(), params_ws.c_str());
+}
+
+} // namespace shell
+
+
OrganizerCore::OrganizerCore(const QSettings &initSettings)
: m_UserInterface(nullptr)
, m_PluginContainer(nullptr)
@@ -1220,6 +1385,212 @@ QStringList OrganizerCore::modsSortedByProfilePriority() const
return res;
}
+bool OrganizerCore::getFileExecutionContext(
+ QWidget* parent, const QFileInfo &targetInfo,
+ QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type)
+{
+ QString extension = targetInfo.suffix();
+ if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) ||
+ (extension.compare("com", Qt::CaseInsensitive) == 0) ||
+ (extension.compare("bat", Qt::CaseInsensitive) == 0)) {
+ binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe");
+ arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
+ type = FileExecutionTypes::Executable;
+ return true;
+ } else if (extension.compare("exe", Qt::CaseInsensitive) == 0) {
+ binaryInfo = targetInfo;
+ type = FileExecutionTypes::Executable;
+ return true;
+ } else if (extension.compare("jar", Qt::CaseInsensitive) == 0) {
+ // types that need to be injected into
+ std::wstring targetPathW = targetInfo.absoluteFilePath().toStdWString();
+ QString binaryPath;
+
+ { // try to find java automatically
+ WCHAR buffer[MAX_PATH];
+ if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) {
+ DWORD binaryType = 0UL;
+ if (!::GetBinaryTypeW(buffer, &binaryType)) {
+ qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError());
+ } else if (binaryType == SCS_32BIT_BINARY) {
+ binaryPath = QString::fromWCharArray(buffer);
+ }
+ }
+ }
+ if (binaryPath.isEmpty() && (extension == "jar")) {
+ // second attempt: look to the registry
+ QSettings javaReg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat);
+ if (javaReg.contains("CurrentVersion")) {
+ QString currentVersion = javaReg.value("CurrentVersion").toString();
+ binaryPath = javaReg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe");
+ }
+ }
+ if (binaryPath.isEmpty()) {
+ binaryPath = QFileDialog::getOpenFileName(
+ parent, QObject::tr("Select binary"), QString(), QObject::tr("Binary") + " (*.exe)");
+ }
+ if (binaryPath.isEmpty()) {
+ return false;
+ }
+ binaryInfo = QFileInfo(binaryPath);
+ if (extension == "jar") {
+ arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
+ } else {
+ arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath()));
+ }
+
+ type = FileExecutionTypes::Executable;
+ return true;
+ } else {
+ type = FileExecutionTypes::Other;
+ return true;
+ }
+}
+
+bool OrganizerCore::executeFileVirtualized(
+ QWidget* parent, const QFileInfo& targetInfo)
+{
+ QFileInfo binaryInfo;
+ QString arguments;
+ FileExecutionTypes type;
+
+ if (!getFileExecutionContext(parent, targetInfo, binaryInfo, arguments, type)) {
+ return false;
+ }
+
+ switch (type)
+ {
+ case FileExecutionTypes::Executable: {
+ spawnBinaryDirect(
+ binaryInfo, arguments, currentProfile()->name(),
+ targetInfo.absolutePath(), "", "");
+
+ return true;
+ }
+
+ case FileExecutionTypes::Other: {
+ ::ShellExecuteW(nullptr, L"open",
+ ToWString(targetInfo.absoluteFilePath()).c_str(),
+ nullptr, nullptr, SW_SHOWNORMAL);
+
+ return true;
+ }
+ }
+
+ // nop
+ 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 bfb72529..9c4e3ae2 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -56,6 +56,20 @@ namespace MOBase {
class IPluginGame;
}
+
+namespace shell
+{
+ bool ExploreFile(const QFileInfo& info);
+ bool ExploreFile(const QString& path);
+ bool ExploreFile(const QDir& dir);
+
+ bool OpenFile(const QString& path);
+ bool OpenLink(const QUrl& url);
+
+ bool Execute(const QString& program, const QString& params);
+}
+
+
class OrganizerCore : public QObject, public MOBase::IPluginDiagnose
{
@@ -87,6 +101,12 @@ private:
typedef boost::signals2::signal<void (const QString&)> SignalModInstalled;
public:
+ enum class FileExecutionTypes
+ {
+ Executable = 1,
+ Other = 2
+ };
+
static bool isNxmLink(const QString &link) { return link.startsWith("nxm://", Qt::CaseInsensitive); }
OrganizerCore(const QSettings &initSettings);
@@ -140,6 +160,14 @@ public:
void doAfterLogin(const std::function<void()> &function) { m_PostLoginTasks.append(function); }
+ static bool getFileExecutionContext(
+ QWidget* parent, const QFileInfo &targetInfo,
+ QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type);
+
+ 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(),
const QString &steamAppID = "",
diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp
index 3d82cf17..9b3e55df 100644
--- a/src/overwriteinfodialog.cpp
+++ b/src/overwriteinfodialog.cpp
@@ -21,6 +21,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "ui_overwriteinfodialog.h"
#include "report.h"
#include "utility.h"
+#include "organizercore.h"
#include <QMessageBox>
#include <QMenu>
#include <QShortcut>
@@ -217,12 +218,7 @@ void OverwriteInfoDialog::renameTriggered()
void OverwriteInfoDialog::openFile(const QModelIndex &index)
{
- QString fileName = m_FileSystemModel->filePath(index);
-
- HINSTANCE res = ::ShellExecuteW(nullptr, L"open", ToWString(fileName).c_str(), nullptr, nullptr, SW_SHOW);
- if ((INT_PTR)res <= 32) {
- qCritical("failed to invoke %s: %d", qUtf8Printable(fileName), res);
- }
+ shell::OpenFile(m_FileSystemModel->filePath(index));
}
@@ -263,7 +259,7 @@ void OverwriteInfoDialog::createDirectoryTriggered()
void OverwriteInfoDialog::on_explorerButton_clicked()
{
- ::ShellExecuteW(nullptr, L"explore", ToWString(m_ModInfo->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::ExploreFile(m_ModInfo->absolutePath());
}
void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint &pos)
diff --git a/src/problemsdialog.cpp b/src/problemsdialog.cpp
index 795baab0..56109d34 100644
--- a/src/problemsdialog.cpp
+++ b/src/problemsdialog.cpp
@@ -1,5 +1,6 @@
#include "problemsdialog.h"
#include "ui_problemsdialog.h"
+#include "organizercore.h"
#include <utility.h>
#include <iplugin.h>
#include <iplugindiagnose.h>
@@ -87,5 +88,5 @@ void ProblemsDialog::startFix()
void ProblemsDialog::urlClicked(const QUrl &url)
{
- ::ShellExecuteW(nullptr, L"open", ToWString(url.toString()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ shell::OpenLink(url);
}
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp
index 4c0f9a8d..271c621b 100644
--- a/src/selfupdater.cpp
+++ b/src/selfupdater.cpp
@@ -31,6 +31,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "settings.h"
#include "bbcode.h"
#include "plugincontainer.h"
+#include "organizercore.h"
#include <versioninfo.h>
#include <report.h>
#include <util.h>
@@ -178,7 +179,7 @@ void SelfUpdater::startUpdate()
tr("New update available (%1)")
.arg(m_UpdateCandidate["tag_name"].toString()), tr("Do you want to install update? All your mods and setup will be left untouched.\nSelect Show Details option to see the full change-log."),
QMessageBox::Yes | QMessageBox::Cancel, m_Parent);
-
+
query.setDetailedText(m_UpdateCandidate["body"].toString());
query.button(QMessageBox::Yes)->setText(tr("Install"));
@@ -329,22 +330,14 @@ void SelfUpdater::downloadCancel()
void SelfUpdater::installUpdate()
{
- const QString mopath
- = QDir::fromNativeSeparators(qApp->property("dataPath").toString());
-
- std::wstring parameters = ToWString("/DIR=\"" + qApp->applicationDirPath() + "\" ");
+ const QString parameters = "/DIR=\"" + qApp->applicationDirPath() + "\" ";
- HINSTANCE res = ::ShellExecuteW(
- nullptr, L"open", m_UpdateFile.fileName().toStdWString().c_str(), parameters.c_str(),
- nullptr, SW_SHOW);
-
- if (res > (HINSTANCE)32) {
+ if (shell::Execute(m_UpdateFile.fileName(), parameters)) {
QCoreApplication::quit();
} else {
- reportError(tr("Failed to start %1: %2")
- .arg(m_UpdateFile.fileName())
- .arg((INT_PTR)res));
+ reportError(tr("Failed to start %1").arg(m_UpdateFile.fileName()));
}
+
m_UpdateFile.remove();
}
diff --git a/src/settings.cpp b/src/settings.cpp
index 231487bb..a844fdc9 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -130,18 +130,19 @@ bool Settings::pluginBlacklisted(const QString &fileName) const
void Settings::registerAsNXMHandler(bool force)
{
- std::wstring nxmPath = ToWString(QCoreApplication::applicationDirPath() + "/nxmhandler.exe");
- std::wstring executable = ToWString(QCoreApplication::applicationFilePath());
- std::wstring mode = force ? L"forcereg" : L"reg";
- std::wstring parameters = mode + L" " + m_GamePlugin->gameShortName().toStdWString();
- for (QString altGame : m_GamePlugin->validShortNames()) {
- parameters += L"," + altGame.toStdWString();
+ const auto nxmPath = QCoreApplication::applicationDirPath() + "/nxmhandler.exe";
+ const auto executable = QCoreApplication::applicationFilePath();
+
+ QString mode = force ? "forcereg" : "reg";
+ QString parameters = mode + " " + m_GamePlugin->gameShortName();
+ for (const QString& altGame : m_GamePlugin->validShortNames()) {
+ parameters += "," + altGame;
}
- parameters += L" \"" + executable + L"\"";
- HINSTANCE res = ::ShellExecuteW(nullptr, L"open", nxmPath.c_str(), parameters.c_str(), nullptr, SW_SHOWNORMAL);
- if ((INT_PTR)res <= 32) {
- QMessageBox::critical(nullptr, tr("Failed"),
- tr("Sorry, failed to start the helper application"));
+ parameters += " \"" + executable + "\"";
+
+ if (!shell::Execute(nxmPath, parameters)) {
+ QMessageBox::critical(
+ nullptr, tr("Failed"), tr("Failed to start the helper application"));
}
}