Albert
Loading...
Searching...
No Matches
plugindependency.h
1// SPDX-FileCopyrightText: 2025 Manuel Schneider
2// SPDX-License-Identifier: MIT
3
4#pragma once
5#include <QCoreApplication>
6#include <albert/app.h>
7#include <albert/export.h>
8#include <albert/logging.h>
9
10namespace albert
11{
12
13template<class T>
14class Dependency
15{
16public:
17
18 inline operator T() const { return dependency_; }
19 inline operator bool() const { return dependency_ != nullptr; }
20 const T* operator->() const { return dependency_; }
21 T* operator->() { return dependency_; }
22 const T* get() const { return dependency_; }
23 T* get() { return dependency_; }
24
25protected:
26
27 Dependency() = default;
28 ~Dependency() = default;
29
30 T *dependency_ = nullptr;
31};
32
44template<class T>
45class ALBERT_EXPORT StrongDependency final : public Dependency<T>
46{
47public:
48
54 StrongDependency(QString id)
55 {
56 try
57 {
58 this->dependency_ = dynamic_cast<T*>(App::instance().extensions().at(id));
59
60 if (!this->dependency_)
61 throw std::runtime_error(
62 QCoreApplication::translate(
63 "Dependency",
64 "Extension '%1' is available, but it is not of the expected type."
65 ).arg(id).toStdString());
66 }
67 catch (const std::out_of_range &)
68 {
69 throw std::runtime_error(
70 QCoreApplication::translate(
71 "Dependency",
72 "The required extension '%1' is not available."
73 ).arg(id).toStdString());
74 }
75 }
76};
77
78
92template<class T>
93class ALBERT_EXPORT WeakDependency final : public Dependency<T>
94{
95public:
96
100 explicit WeakDependency(const QString &id, std::function<void(bool)> on_registered = {}):
101 callback(on_registered),
102 id_(id)
103 {
104 try {
105 this->dependency_ = dynamic_cast<T*>(App::instance().extensions().at(id));
106 if (!this->dependency_)
107 WARN << QStringLiteral("Found '%1' but failed casting to expected type.").arg(id);
108 } catch (const std::out_of_range &) { /* okay, optional */ }
109
110 conn_add_ = QObject::connect(&App::instance(), &App::added,
111 [this](Extension *e){ onRegistered(e);});
112
113 conn_rem_ = QObject::connect(&App::instance(), &App::removed,
114 [this](Extension *e){ onDeregistered(e);});
115 }
116
117 ~WeakDependency()
118 {
119 QObject::disconnect(conn_add_);
120 QObject::disconnect(conn_rem_);
121 }
122
123 std::function<void(bool)> callback;
124
125private:
126
127 void onRegistered(Extension *e)
128 {
129 if (e->id() != this->id_)
130 return;
131
132 if (!this->dependency_)
133 {
134 if (auto *d = dynamic_cast<T*>(e); d)
135 {
136 this->dependency_ = d;
137 if (callback)
138 callback(true);
139 }
140 else
141 WARN << QStringLiteral("Failed casting '%1' to expected type.").arg(this->id_);
142 }
143 else
144 CRIT << "WeakDependency already set. Internal logic error?";
145 }
146
147 void onDeregistered(Extension *e)
148 {
149
150 if (e->id() != this->id_)
151 return;
152
153 if (this->dependency_)
154 {
155 if (auto *d = dynamic_cast<T*>(e); d)
156 {
157 if (callback)
158 callback(false); // the dependency should still be usable in the callback
159 this->dependency_ = nullptr;
160 }
161 else
162 WARN << QStringLiteral("Failed casting '%1' to expected type.").arg(this->id_);
163 }
164 else
165 CRIT << "WeakDependency already unset. Internal logic error?";
166 }
167
168 QMetaObject::Connection conn_add_;
169 QMetaObject::Connection conn_rem_;
170 QString id_;
171
172};
173
174}
Convenience holder class for hard plugin dependencies.
Definition plugindependency.h:46
StrongDependency(QString id)
Constructs a StrongDependency with id.
Definition plugindependency.h:54
Convenience holder class for soft plugin dependencies.
Definition plugindependency.h:94
WeakDependency(const QString &id, std::function< void(bool)> on_registered={})
Constructs a WeakDependency with id and callback on_registered.
Definition plugindependency.h:100
The Albert namespace.
Definition app.h:55