summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Rimpo <jeremy.rimpo@servermonkey.com>2024-07-11 09:46:29 -0500
committerGitHub <noreply@github.com>2024-07-11 16:46:29 +0200
commit193442e77362edfdb55636f907a14098be59fd2a (patch)
tree9b2a1726857cedc6785afcec942a6e696f498ce7
parenta4f6298111b9b4518d00e6df3a53dd176858dd34 (diff)
Archive preview support (#2056)
* Support for archive file previews - Should account for alternates - Extracts files and requests preview from plugins that claim support
-rw-r--r--.github/workflows/build.yml2
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/filetree.cpp8
-rw-r--r--src/modinfodialog.cpp6
-rw-r--r--src/modinfodialogimages.cpp2
-rw-r--r--src/organizercore.cpp27
-rw-r--r--src/previewgenerator.cpp22
-rw-r--r--src/previewgenerator.h4
8 files changed, 54 insertions, 20 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 89f3bc7c..c5857574 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,5 +16,5 @@ jobs:
qt-modules: qtpositioning qtwebchannel qtwebengine qtwebsockets
mo2-third-parties:
7z zlib gtest libbsarch libloot openssl bzip2 python lz4 spdlog
- boost boost-di sip pyqt pybind11 ss licenses explorerpp
+ boost boost-di sip pyqt pybind11 ss licenses explorerpp DirectXTex
mo2-dependencies: usvfs cmake_common uibase githubpp bsatk esptk archive lootcli game_gamebryo
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 10459e7e..7188c03b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,8 +7,9 @@ mo2_configure_executable(organizer
EXTRA_TRANSLATIONS ${MO2_SUPER_PATH}/game_gamebryo/src ${MO2_UIBASE_PATH}/src
PRIVATE_DEPENDS
uibase githubpp bsatk esptk archive usvfs lootcli boost::program_options
- Qt::WebEngineWidgets Qt::WebSockets)
+ DirectXTex libbsarch Qt::WebEngineWidgets Qt::WebSockets)
target_link_libraries(organizer PUBLIC Shlwapi)
+target_include_directories(organizer PUBLIC ${DDS_ROOT})
mo2_install_target(organizer)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/dlls.manifest.qt6"
diff --git a/src/filetree.cpp b/src/filetree.cpp
index f043448f..6d397f24 100644
--- a/src/filetree.cpp
+++ b/src/filetree.cpp
@@ -246,16 +246,12 @@ void FileTree::activate(FileTreeItem* item)
return;
}
- if (item->isFromArchive()) {
- log::warn("cannot activate file from archive '{}'", item->filename());
- return;
- }
-
const auto tryPreview = m_core.settings().interface().doubleClicksOpenPreviews();
if (tryPreview) {
const QFileInfo fi(item->realPath());
- if (m_plugins.previewGenerator().previewSupported(fi.suffix().toLower())) {
+ if (m_plugins.previewGenerator().previewSupported(fi.suffix().toLower(),
+ item->isFromArchive())) {
preview(item);
return;
}
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index d0e8d1ad..1798e987 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -42,12 +42,8 @@ const int max_scan_for_context_menu = 50;
bool canPreviewFile(const PluginContainer& pluginContainer, bool isArchive,
const QString& filename)
{
- if (isArchive) {
- return false;
- }
-
const auto ext = QFileInfo(filename).suffix().toLower();
- return pluginContainer.previewGenerator().previewSupported(ext);
+ return pluginContainer.previewGenerator().previewSupported(ext, isArchive);
}
bool isExecutableFilename(const QString& filename)
diff --git a/src/modinfodialogimages.cpp b/src/modinfodialogimages.cpp
index 1042eaca..7b250e1e 100644
--- a/src/modinfodialogimages.cpp
+++ b/src/modinfodialogimages.cpp
@@ -262,7 +262,7 @@ void ImagesTab::select(std::size_t i, Visibility v)
ui->imagesPath->setText(QDir::toNativeSeparators(f->path()));
ui->imagesExplore->setEnabled(true);
if (plugin().previewGenerator().previewSupported(
- QFileInfo(f->path()).suffix().toLower()))
+ QFileInfo(f->path()).suffix().toLower(), false))
ui->previewPluginButton->setEnabled(true);
else
ui->previewPluginButton->setEnabled(false);
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index f471ead1..0f6a1455 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -71,6 +71,8 @@
#include <tuple>
#include <utility>
+#include "bs_archive.h"
+
#include "organizerproxy.h"
using namespace MOShared;
@@ -1053,7 +1055,7 @@ bool OrganizerCore::previewFileWithAlternatives(QWidget* parent, QString fileNam
// set up preview dialog
PreviewDialog preview(fileName, parent);
- auto addFunc = [&](int originId) {
+ auto addFunc = [&](int originId, std::wstring archiveName = L"") {
FilesOrigin& origin = directoryStructure()->getOriginByID(originId);
QString filePath =
QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName;
@@ -1066,14 +1068,33 @@ bool OrganizerCore::previewFileWithAlternatives(QWidget* parent, QString fileNam
} else {
preview.addVariant(ToQString(origin.getName()), wid);
}
+ } else if (archiveName != L"") {
+ auto archiveFile = directoryStructure()->searchFile(archiveName);
+ if (archiveFile.get() != nullptr) {
+ try {
+ libbsarch::bs_archive archiveLoader;
+ archiveLoader.load_from_disk(archiveFile->getFullPath());
+ libbsarch::memory_blob fileData =
+ archiveLoader.extract_to_memory(fileName.toStdWString());
+ QByteArray convertedFileData((char*)(fileData.data), fileData.size);
+ QWidget* wid = m_PluginContainer->previewGenerator().genArchivePreview(
+ convertedFileData, filePath);
+ if (wid == nullptr) {
+ reportError(tr("failed to generate preview for %1").arg(filePath));
+ } else {
+ preview.addVariant(ToQString(origin.getName()), wid);
+ }
+ } catch (std::exception& e) {
+ }
+ }
}
};
if (selectedOrigin == -1) {
// don't bother with the vector of origins, just add them as they come
- addFunc(file->getOrigin());
+ addFunc(file->getOrigin(), file->isFromArchive() ? file->getArchive().name() : L"");
for (const auto& alt : file->getAlternatives()) {
- addFunc(alt.originID());
+ addFunc(alt.originID(), alt.isFromArchive() ? alt.archive().name() : L"");
}
} else {
std::vector<int> origins;
diff --git a/src/previewgenerator.cpp b/src/previewgenerator.cpp
index ba73c065..dad41c2f 100644
--- a/src/previewgenerator.cpp
+++ b/src/previewgenerator.cpp
@@ -35,12 +35,16 @@ PreviewGenerator::PreviewGenerator(const PluginContainer& pluginContainer)
m_MaxSize = QGuiApplication::primaryScreen()->size() * 0.8;
}
-bool PreviewGenerator::previewSupported(const QString& fileExtension) const
+bool PreviewGenerator::previewSupported(const QString& fileExtension,
+ const bool& isArchive) const
{
auto& previews = m_PluginContainer.plugins<IPluginPreview>();
for (auto* preview : previews) {
if (preview->supportedExtensions().contains(fileExtension)) {
- return true;
+ if (!isArchive)
+ return true;
+ if (preview->supportsArchives())
+ return true;
}
}
return false;
@@ -58,3 +62,17 @@ QWidget* PreviewGenerator::genPreview(const QString& fileName) const
}
return nullptr;
}
+
+QWidget* PreviewGenerator::genArchivePreview(const QByteArray& fileData,
+ const QString& fileName) const
+{
+ const QString ext = QFileInfo(fileName).suffix().toLower();
+ auto& previews = m_PluginContainer.plugins<IPluginPreview>();
+ for (auto* preview : previews) {
+ if (m_PluginContainer.isEnabled(preview) &&
+ preview->supportedExtensions().contains(ext) && preview->supportsArchives()) {
+ return preview->genDataPreview(fileData, fileName, m_MaxSize);
+ }
+ }
+ return nullptr;
+}
diff --git a/src/previewgenerator.h b/src/previewgenerator.h
index dd0d2cd4..15d652f6 100644
--- a/src/previewgenerator.h
+++ b/src/previewgenerator.h
@@ -33,10 +33,12 @@ class PreviewGenerator
public:
PreviewGenerator(const PluginContainer& pluginContainer);
- bool previewSupported(const QString& fileExtension) const;
+ bool previewSupported(const QString& fileExtension, const bool& isArchive) const;
QWidget* genPreview(const QString& fileName) const;
+ QWidget* genArchivePreview(const QByteArray& fileData, const QString& fileName) const;
+
private:
const PluginContainer& m_PluginContainer;
QSize m_MaxSize;