Création d’un plugin aLTAG3D

Afin de permettre à aLTAG3D de remplir de manière automatique le plus grand nombre d’informations possible, un système de plugin a été mis en place.

Lors de l’importation d’un fichier dans le projet d’archivage, aLTAG3D cherche dans la liste des plugins disponible celui étant compatible avec le format du fichier importé. Si il existe, ce plugin pourra communiquer au logiciel un ensemble d’informations concernant le fichier, qui viendront compléter les données du projet.

Le système de plugins mis en place est celui de Qt, dont la documentation est disponible ici.

L’interface plugin dans aLTAG3D

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef INTERFACES_H
#define INTERFACES_H

#include <QtPlugin>

QT_BEGIN_NAMESPACE
class QString;
class QStringList;
class QJsonObject;
QT_END_NAMESPACE

class PluginInterface
{
public:
    virtual ~PluginInterface() {}
    virtual QString author() const = 0;
    virtual QString version() const = 0;
    virtual QString title() const = 0;
    virtual QStringList exportableData() const = 0;
    virtual QStringList formats() const = 0;
    virtual QJsonObject extractData(const QString &filename, const QStringList &dataToExtract, QWidget *parent) = 0;
    virtual QString fileDescription() const = 0;
};

QT_BEGIN_NAMESPACE
#define PluginInterface_iid "fr.cnrs.archeovision.aLTAG3d.PluginInterface"

Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)
QT_END_NAMESPACE

#endif

Exemple de plugin simple

Fichier .pro :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#-------------------------------------------------
#
# Exemple de fichier .pro pour un plugin altag3d
# inspiré de la documentation Qt
#
#-------------------------------------------------

TEMPLATE      = lib
CONFIG       += plugin
QT           += widgets
INCLUDEPATH  += inc
HEADERS       = exampleplugin.h \
                inc/interfaces.h
SOURCES       = exampleplugin.cpp
TARGET        = altag3d_example_plugin
DESTDIR       = ../plugins

target.path = ../../plugins
INSTALLS += target

CONFIG += install_ok  # Do not cargo-cult this!
uikit: CONFIG += debug_and_release
exampleplugin.cpp :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "exampleplugin.h"

#include <QtWidgets>
#include <QMessageBox>

QString
ExamplePlugin::author() const
{
    //Auteur du plugin
    return QString("Archeovision");
}

QString
ExamplePlugin::version() const
{
    //Version du plugin
    return QString("v1.0");
}

QString
ExamplePlugin::title() const
{
    //Nom du plugin
    return QString("JPEG/JPG plugin example");
}

QStringList
ExamplePlugin::exportableData() const
{
    //La liste des données renvoyées par le plugin
    QStringList list;
    //Données "Fichier"
    list << tr("Chemin du fichier");
    list << tr("Créateur");
    list << tr("Date du fichier");
    list << tr("Format du fichier");
    list << tr("Empreinter ORI");
    //Données spécifique au JPEG
    //EXIF par exemple
    return list;
}

QStringList
ExamplePlugin::formats() const
{
    //Les formats que le plugin traite
    QStringList list;
    list << "jpg";
    list << "jpeg";
    return list;
}

QJsonObject
ExamplePlugin::extractData(const QString &filename, const QStringList &dataToExtract, QWidget *parent)
{
    QJsonObject object;
    QFileInfo fi = QFileInfo(filename);
    if (dataToExtract.contains("cheminFichier"))
    {
        object["cheminFichier"] = filename;
    }
    if (dataToExtract.contains("createur"))
    {
        object["createur"] = fi.owner();
    }
    if (dataToExtract.contains("formatFichier"))
    {
        //fi.completeSuffix().toUpper() en principe mais pas ici : "jpg" != "jpeg"
        object["formatFichier"] = "JPEG";
    }
    if (dataToExtract.contains("dateFichier"))
    {
        object["dateFichier"] = fi.created().toString();
    }
    if (dataToExtract.contains("empreinteOri"))
    {
        QString hash = QString("MD5@");
        QByteArray hashHex = fileChecksum(filename,QCryptographicHash::Md5);
        hash += QString::fromUtf8(hashHex);
        object["empreinteOri"] = hash;
    }
    //On retourne l'objet JSON
    return object;
}

QString
ExamplePlugin::fileDescription() const
{
    //"Un fichier <type> au format ..."
    return QString("image");
}
exampleplugin.h :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#ifndef EXAMPLEPLUGIN_H
#define EXAMPLEPLUGIN_H

#include <interfaces.h>

#include <QObject>
#include <QtPlugin>
#include <QStringList>
#include <QFileInfo>
#include <QByteArray>
#include <QCryptographicHash>
#include <QString>
#include <QDateTime>

class ExamplePlugin : public QObject, public PluginInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "fr.cnrs.archeovision.aLTAG3d.PluginInterface" FILE "pluginsfilters.json")
    Q_INTERFACES(PluginInterface)

public:
    QString author() const override;
    QString version() const override;
    QString title() const override;
    QStringList exportableData() const override;
    QStringList formats() const override;
    QJsonObject extractData(const QString &filename, const QStringList &dataToExtract, QWidget *parent) override;
    QString fileDescription() const override;

private:
    QByteArray fileChecksum(const QString &filename,
                            QCryptographicHash::Algorithm hashAlgorithm)
    {
        //Permet de générer une empreinte pour un fichier (Attention aux gros fichiers)
        QFile f(filename);
        if (f.open(QFile::ReadOnly)) {
            QCryptographicHash hash(hashAlgorithm);
            if (hash.addData(&f)) {
                return hash.result().toHex();
            }
        }
        return QByteArray();
    }
};

#endif // EXAMPLEPLUGIN_H
pluginsfilters.json :
1
{}

Le fichier pluginsfilters.json est presque vide, mais nécessaire à la compilation.