File indexing completed on 2024-05-12 04:55:39

0001 /**
0002  * \file kid3qmlplugin.cpp
0003  * QML plugin for Kid3 application.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 19 Sep 2014
0008  *
0009  * Copyright (C) 2014-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #include "kid3qmlplugin.h"
0028 #include <QCoreApplication>
0029 #include <QQmlComponent>
0030 #include <QQmlContext>
0031 #include "kid3application.h"
0032 #include "guiplatformtools.h"
0033 #include "qmlimageprovider.h"
0034 #include "fileproxymodel.h"
0035 #include "dirproxymodel.h"
0036 #include "genremodel.h"
0037 #include "frametablemodel.h"
0038 #include "framelist.h"
0039 #include "frameeditorobject.h"
0040 #include "frameobjectmodel.h"
0041 #include "taggedfileselection.h"
0042 #include "scriptutils.h"
0043 #include "configobjects.h"
0044 #include "formatconfig.h"
0045 #include "playlistconfig.h"
0046 #include "tagconfig.h"
0047 #include "checkablelistmodel.h"
0048 #include "dirrenamer.h"
0049 #include "filefilter.h"
0050 #include "batchimporter.h"
0051 #include "downloadclient.h"
0052 #include "config.h"
0053 #ifdef HAVE_QTMULTIMEDIA
0054 #include "audioplayer.h"
0055 #endif
0056 
0057 Q_DECLARE_METATYPE(Kid3Application*)
0058 Q_DECLARE_METATYPE(QAbstractItemModel*)
0059 Q_DECLARE_METATYPE(FileProxyModel*)
0060 Q_DECLARE_METATYPE(DirProxyModel*)
0061 Q_DECLARE_METATYPE(GenreModel*)
0062 Q_DECLARE_METATYPE(FrameTableModel*)
0063 Q_DECLARE_METATYPE(FrameList*)
0064 Q_DECLARE_METATYPE(FrameEditorObject*)
0065 Q_DECLARE_METATYPE(FrameObjectModel*)
0066 Q_DECLARE_METATYPE(TaggedFileSelectionTagContext*)
0067 Q_DECLARE_METATYPE(TaggedFileSelection*)
0068 Q_DECLARE_METATYPE(QList<QPersistentModelIndex>)
0069 Q_DECLARE_METATYPE(Frame::TagVersion)
0070 Q_DECLARE_METATYPE(Frame::TagNumber)
0071 Q_DECLARE_METATYPE(Frame)
0072 Q_DECLARE_METATYPE(ScriptUtils*)
0073 Q_DECLARE_METATYPE(ConfigObjects*)
0074 Q_DECLARE_METATYPE(CheckableListModel*)
0075 Q_DECLARE_METATYPE(QItemSelectionModel*)
0076 Q_DECLARE_METATYPE(DirRenamer*)
0077 Q_DECLARE_METATYPE(BatchImporter*)
0078 Q_DECLARE_METATYPE(DownloadClient*)
0079 Q_DECLARE_METATYPE(Kid3ApplicationTagContext*)
0080 #ifdef HAVE_QTMULTIMEDIA
0081 Q_DECLARE_METATYPE(AudioPlayer*)
0082 #endif
0083 
0084 namespace {
0085 
0086 /**
0087  * Get the plugins path from the QML import path.
0088  *
0089  * The plugins path is normally found relative to the directory where the
0090  * application binary is located. However, when the application is started
0091  * from a QML script using qmlscene, the path plugins path cannot be found
0092  * from the location of qmlscene. In this case, the plugins path can be
0093  * derived from the QML import path, which contains the Kid3 QML plugin.
0094  *
0095  * @param engine QML engine
0096  * @return plugins directory path, empty if not found.
0097  */
0098 QString getPluginsPathFromImportPathList(const QQmlEngine* engine)
0099 {
0100   QString cfgPluginsDir(QLatin1String(CFG_PLUGINSDIR));
0101   if (cfgPluginsDir.startsWith(QLatin1String("./"))) {
0102     cfgPluginsDir.remove(0, 2);
0103   } else if (cfgPluginsDir.startsWith(QLatin1String("../"))) {
0104     cfgPluginsDir.remove(0, 3);
0105   }
0106 
0107   QString pluginsPath;
0108   const auto paths = engine->importPathList();
0109   for (const QString& path : paths) {
0110     if (int index = path.indexOf(cfgPluginsDir); index != -1) {
0111       pluginsPath = path.left(index + cfgPluginsDir.length());
0112       break;
0113     } else if (pluginsPath.isEmpty() &&
0114                (index = path.indexOf(QLatin1String("plugins"))) != -1) {
0115       pluginsPath = path.left(index + 7);
0116       // Probably a path in the build directory, use it if CFG_PLUGINSDIR is
0117       // not found.
0118     }
0119   }
0120   return pluginsPath;
0121 }
0122 
0123 }
0124 
0125 /**
0126  * Constructor.
0127  * @param parent parent object
0128  */
0129 Kid3QmlPlugin::Kid3QmlPlugin(QObject* parent)
0130   : QQmlExtensionPlugin(parent),
0131     m_platformTools(nullptr), m_kid3App(nullptr), m_imageProvider(nullptr),
0132     m_ownsKid3App(false)
0133 {
0134 }
0135 
0136 /**
0137  * Destructor.
0138  */
0139 Kid3QmlPlugin::~Kid3QmlPlugin()
0140 {
0141   if (m_ownsKid3App) {
0142     delete m_kid3App;
0143     delete m_platformTools;
0144   }
0145 }
0146 
0147 /**
0148  * Register the types used by the QML plugin.
0149  * @param uri URI of imported module, must be "Kid3"
0150  */
0151 void Kid3QmlPlugin::registerTypes(const char *uri)
0152 {
0153   if (qstrcmp(uri, "Kid3") == 0) {
0154     qRegisterMetaType<QList<QPersistentModelIndex> >();
0155     qRegisterMetaType<Frame::TagVersion>();
0156     qRegisterMetaType<Frame::TagNumber>();
0157     qRegisterMetaType<QAbstractItemModel*>();
0158     // @uri Kid3
0159     qmlRegisterUncreatableType<Kid3Application>(uri, 1, 1, "Kid3Application",
0160         QLatin1String("Retrieve it using app"));
0161     qmlRegisterUncreatableType<FileProxyModel>(uri, 1, 0, "FileProxyModel",
0162         QLatin1String("Retrieve it using app.fileProxyModel"));
0163     qmlRegisterUncreatableType<DirProxyModel>(uri, 1, 0, "DirProxyModel",
0164         QLatin1String("Retrieve it using app.dirProxyModel"));
0165     qmlRegisterUncreatableType<GenreModel>(uri, 1, 0, "GenreModel",
0166         QLatin1String("Retrieve it using app.tag().genreModel"));
0167     qmlRegisterUncreatableType<FrameTableModel>(uri, 1, 0, "FrameTableModel",
0168         QLatin1String("Retrieve it using app.tag().frameModel"));
0169     qmlRegisterUncreatableType<FrameList>(uri, 1, 0, "FrameList",
0170         QLatin1String("Retrieve it using app.tag().frameList"));
0171     qmlRegisterType<FrameEditorObject>(uri, 1, 0, "FrameEditorObject");
0172     qmlRegisterUncreatableType<FrameObjectModel>(uri, 1, 0, "FrameObjectModel",
0173         QLatin1String("Argument of FrameEditorObject.frameEditFinished()"));
0174     qmlRegisterUncreatableType<TaggedFileSelection>(
0175           uri, 1, 0, "TaggedFileSelection",
0176         QLatin1String("Retrieve it using app.selectionInfo"));
0177     qmlRegisterUncreatableType<TaggedFileSelectionTagContext>(uri, 1, 0,
0178         "TaggedFileSelectionTagContext",
0179         QLatin1String("Retrieve it using app.selectionInfo.tag()"));
0180     qmlRegisterUncreatableType<QItemSelectionModel>(
0181           uri, 1, 0, "QItemSelectionModel",
0182         QLatin1String("Retrieve it using app.fileSelectionModel"));
0183     qmlRegisterType<ScriptUtils>(uri, 1, 0, "ScriptUtils");
0184     qmlRegisterType<ConfigObjects>(uri, 1, 0, "ConfigObjects");
0185     qmlRegisterType<CheckableListModel>(uri, 1, 0, "CheckableListModel");
0186     qmlRegisterUncreatableType<Frame>(uri, 1, 0, "Frame",
0187                                       QLatin1String("Only enum container"));
0188     qmlRegisterUncreatableType<FrameNotice>(uri, 1, 0, "FrameNotice",
0189                                           QLatin1String("Only enum container"));
0190     qmlRegisterUncreatableType<FormatConfig>(
0191           uri, 1, 0, "FormatConfig", QLatin1String("Only enum container"));
0192     qmlRegisterUncreatableType<PlaylistConfig>(
0193           uri, 1, 0, "PlaylistConfig", QLatin1String("Only enum container"));
0194     qmlRegisterUncreatableType<TagConfig>(
0195           uri, 1, 0, "TagConfig", QLatin1String("Only enum container"));
0196     qmlRegisterUncreatableType<DirRenamer>(uri, 1, 0, "DirRenamer",
0197         QLatin1String("Retrieve it using app.dirRenamer"));
0198     qmlRegisterUncreatableType<FileFilter>(
0199           uri, 1, 0, "FileFilter", QLatin1String("Only enum container"));
0200     qmlRegisterUncreatableType<BatchImporter>(uri, 1, 0, "BatchImporter",
0201         QLatin1String("Retrieve it using app.batchImporter"));
0202     qmlRegisterUncreatableType<DownloadClient>(uri, 1, 0, "DownloadClient",
0203         QLatin1String("Retrieve it using app.downloadClient"));
0204     qmlRegisterUncreatableType<Kid3ApplicationTagContext>(uri, 1, 0,
0205         "Kid3ApplicationTagContext",
0206         QLatin1String("Retrieve it using app.tag()"));
0207 #ifdef HAVE_QTMULTIMEDIA
0208     qmlRegisterUncreatableType<AudioPlayer>(uri, 1, 0, "AudioPlayer",
0209         QLatin1String("Retrieve it using app.getAudioPlayer()"));
0210 #endif
0211   }
0212 }
0213 
0214 /**
0215  * Initialize the QML engine when the plugin is imported.
0216  * @param engine QML engine
0217  * @param uri URI of imported module, must be "Kid3"
0218  */
0219 void Kid3QmlPlugin::initializeEngine(QQmlEngine* engine, const char* uri)
0220 {
0221   if (qstrcmp(uri, "Kid3") == 0) {
0222     Kid3Application::setPluginsPathFallback(
0223           getPluginsPathFromImportPathList(engine));
0224     QQmlContext* rootContext = engine->rootContext();
0225     m_kid3App = qvariant_cast<Kid3Application*>(
0226           rootContext->contextProperty(QLatin1String("app")));
0227     if (!m_kid3App) {
0228       m_platformTools = new GuiPlatformTools;
0229       m_kid3App = new Kid3Application(m_platformTools);
0230       m_ownsKid3App = true;
0231       rootContext->setContextProperty(QLatin1String("app"), m_kid3App);
0232     }
0233     if (!m_imageProvider) {
0234       m_imageProvider = new QmlImageProvider(
0235             m_kid3App->getFileProxyModel()->getIconProvider());
0236     }
0237     m_kid3App->setImageProvider(m_imageProvider);
0238     // The QQmlEngine takes ownership of m_imageProvider.
0239     engine->addImageProvider(QLatin1String("kid3"), m_imageProvider);
0240   }
0241 }