mirror of https://github.com/qt/qtdoc.git
240 lines
6.1 KiB
C++
240 lines
6.1 KiB
C++
// Copyright (C) 2023 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
|
|
#include "abstractviewer.h"
|
|
#include "viewerfactory.h"
|
|
#include "viewerinterfaces.h"
|
|
|
|
#include <QApplication>
|
|
#include <QMessageBox>
|
|
#include <QWidget>
|
|
|
|
#include <QDir>
|
|
#include <QMimeDatabase>
|
|
#include <QMimeType>
|
|
#include <QPluginLoader>
|
|
#include <QTimer>
|
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
namespace {
|
|
struct Tr {
|
|
Q_DECLARE_TR_FUNCTIONS(ViewerFactory);
|
|
};
|
|
}
|
|
|
|
ViewerFactory::ViewerFactory(QWidget *displayWidget, QMainWindow *mainWindow, DefaultPolicy policy)
|
|
: m_defaultPolicy(policy),
|
|
m_displayWidget(displayWidget),
|
|
m_mainWindow(mainWindow)
|
|
{
|
|
Q_ASSERT(m_displayWidget);
|
|
Q_ASSERT(m_mainWindow);
|
|
loadViewerPlugins();
|
|
}
|
|
|
|
ViewerFactory::~ViewerFactory()
|
|
{
|
|
unload();
|
|
}
|
|
|
|
AbstractViewer *ViewerFactory::viewer(QFile *file) const
|
|
{
|
|
Q_ASSERT(file);
|
|
|
|
const QFileInfo info(*file);
|
|
|
|
// Find via extension
|
|
AbstractViewer *viewer = ViewerFactory::viewer(info.suffix());
|
|
|
|
// Find via mime type
|
|
if (!viewer) {
|
|
QMimeDatabase db;
|
|
const auto mimeType = db.mimeTypeForFile(info);
|
|
viewer = ViewerFactory::viewer(mimeType);
|
|
if (!viewer) {
|
|
qWarning() << "Mime type" << mimeType.name() << "not supported.";
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
Q_ASSERT(viewer);
|
|
viewer->init(file, m_displayWidget, m_mainWindow);
|
|
return viewer;
|
|
}
|
|
|
|
//! [loader]
|
|
void ViewerFactory::loadViewerPlugins()
|
|
{
|
|
if (!m_viewers.isEmpty())
|
|
return;
|
|
//! [loader]
|
|
|
|
//! [static]
|
|
// Load static plugins
|
|
const QObjectList &staticPlugins = QPluginLoader::staticInstances();
|
|
for (auto *plugin : staticPlugins)
|
|
addViewer(plugin);
|
|
//! [static]
|
|
|
|
//! [shared]
|
|
// Load shared plugins
|
|
QDir pluginsDir = QDir(QApplication::applicationDirPath());
|
|
|
|
#if defined(Q_OS_WINDOWS)
|
|
pluginsDir.cd("app"_L1);
|
|
#elif defined(Q_OS_DARWIN)
|
|
if (pluginsDir.dirName() == "MacOS"_L1) {
|
|
pluginsDir.cdUp();
|
|
pluginsDir.cdUp();
|
|
pluginsDir.cdUp();
|
|
}
|
|
#endif
|
|
const auto entryList = pluginsDir.entryList(QDir::Files);
|
|
for (const QString &fileName : entryList) {
|
|
QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
|
|
QObject *plugin = loader.instance();
|
|
if (plugin)
|
|
addViewer(plugin);
|
|
#if 0
|
|
else
|
|
qDebug() << loader.errorString();
|
|
#endif
|
|
}
|
|
}
|
|
//! [shared]
|
|
|
|
void ViewerFactory::unload()
|
|
{
|
|
qDeleteAll(viewers());
|
|
m_viewers.clear();
|
|
}
|
|
|
|
void ViewerFactory::addViewer(QObject *viewerObject)
|
|
{
|
|
auto *interface = qobject_cast<ViewerInterface *>(viewerObject);
|
|
if (!interface)
|
|
return;
|
|
|
|
// discard viewers, which don't support any MIME types
|
|
if (interface->supportedMimeTypes().isEmpty()) {
|
|
delete interface;
|
|
return;
|
|
}
|
|
|
|
// Set custom default viewer
|
|
if (interface->viewer()->isDefaultViewer())
|
|
m_defaultViewer = interface->viewer();
|
|
|
|
m_viewers.insert(interface->viewerName(), interface->viewer());
|
|
}
|
|
|
|
QStringList ViewerFactory::viewerNames(bool showDefault) const
|
|
{
|
|
if (!showDefault)
|
|
return m_viewers.keys();
|
|
|
|
QStringList list;
|
|
for (auto it = m_viewers.constBegin(); it != m_viewers.constEnd(); ++it) {
|
|
QString name = it.key();
|
|
if ((m_defaultViewer && it.value()->isDefaultViewer())
|
|
|| (!m_defaultViewer && it.key() == "TxtViewer"_L1)) {
|
|
name += "(default)"_L1;
|
|
}
|
|
list.append(name);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
ViewerFactory::ViewerList ViewerFactory::viewers() const
|
|
{
|
|
return m_viewers.values();
|
|
}
|
|
|
|
AbstractViewer *ViewerFactory::findViewer(const QString &viewerName) const
|
|
{
|
|
const ViewerList &viewerList = viewers();
|
|
for (auto *viewer : viewerList) {
|
|
if (viewer->viewerName() == viewerName)
|
|
return viewer;
|
|
}
|
|
qWarning() << "Plugin" << viewerName << "not loaded.";
|
|
return nullptr;
|
|
}
|
|
|
|
AbstractViewer *ViewerFactory::viewer(const QMimeType &mimeType) const
|
|
{
|
|
const ViewerList &viewerList = viewers();
|
|
|
|
for (AbstractViewer *viewer : viewerList) {
|
|
for (const QString &type : viewer->supportedMimeTypes()) {
|
|
if (mimeType.inherits(type))
|
|
return viewer;
|
|
}
|
|
}
|
|
|
|
AbstractViewer *viewer = defaultViewer();
|
|
if (!viewer) {
|
|
QMessageBox mbox;
|
|
mbox.setIcon(QMessageBox::Warning);
|
|
mbox.setText(Tr::tr("No viewers for the chosen file format."));
|
|
mbox.setStandardButtons(QMessageBox::Ok);
|
|
QTimer::singleShot(8000, &mbox, [&mbox]() { mbox.close(); });
|
|
mbox.exec();
|
|
return nullptr;
|
|
}
|
|
|
|
if (m_defaultWarning) {
|
|
QMessageBox mbox;
|
|
mbox.setIcon(QMessageBox::Warning);
|
|
mbox.setText(Tr::tr("Mime type %1 not supported. Falling back to %2.")
|
|
.arg(mimeType.name(), viewer->viewerName()));
|
|
mbox.setStandardButtons(QMessageBox::Ok);
|
|
QTimer::singleShot(8000, &mbox, [&mbox](){ mbox.close(); });
|
|
mbox.exec();
|
|
}
|
|
|
|
return viewer;
|
|
}
|
|
|
|
AbstractViewer *ViewerFactory::viewer(const QString &extension) const
|
|
{
|
|
const ViewerList &viewerList = viewers();
|
|
for (AbstractViewer *viewer : viewerList) {
|
|
if (viewer->supportedExtensions().contains(extension))
|
|
return viewer;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
AbstractViewer *ViewerFactory::defaultViewer() const
|
|
{
|
|
switch (m_defaultPolicy) {
|
|
case DefaultPolicy::NeverDefault:
|
|
return nullptr;
|
|
case DefaultPolicy::DefaultToCustomViewer:
|
|
return m_defaultViewer ? m_defaultViewer : findViewer("TxtViewer"_L1);
|
|
case DefaultPolicy::DefaultToTxtViewer:
|
|
return findViewer("TxtViewer"_L1);
|
|
}
|
|
Q_UNREACHABLE();
|
|
}
|
|
|
|
QStringList ViewerFactory::supportedMimeTypes() const
|
|
{
|
|
static QStringList mimeTypes;
|
|
if (!mimeTypes.isEmpty())
|
|
return mimeTypes;
|
|
|
|
const ViewerList &viewerList = viewers();
|
|
for (auto viewer : viewerList) {
|
|
mimeTypes.append(viewer->supportedMimeTypes());
|
|
const QStringList &extensions = viewer->supportedExtensions();
|
|
if (extensions.isEmpty())
|
|
continue;
|
|
mimeTypes << (Tr::tr("Plus extensions: %1").arg(extensions.join(","_L1)));
|
|
}
|
|
|
|
return mimeTypes;
|
|
}
|