239 lines
7.6 KiB
C++
239 lines
7.6 KiB
C++
#ifndef APPLICATION_CONNECTOR_H
|
|
#define APPLICATION_CONNECTOR_H
|
|
|
|
#include <QList>
|
|
#include <QPair>
|
|
#include <QVariant>
|
|
|
|
// WARNING: Not used directly in cpp file
|
|
// You can transfer it to the cpp file, it will not be an error, but a
|
|
// warning will remain
|
|
#include "base_sql_table_model.h"
|
|
#include "data_repository_signals.h"
|
|
#include "entity_finder_widget.h"
|
|
|
|
// Forward declarations
|
|
class ModelManager;
|
|
class RepositoryManager;
|
|
|
|
class ApplicationConnector {
|
|
private:
|
|
// WARNING: Not use directly in cpp file
|
|
|
|
template <typename SenderType, typename ReceiverType>
|
|
using Link = QPair<SenderType *, ReceiverType *>;
|
|
|
|
template <typename SignalType, typename SlotType>
|
|
using Connection = QPair<SignalType, SlotType>;
|
|
|
|
template <typename SenderType, typename ReceiverType>
|
|
using ConnectionVariant = std::variant<
|
|
Connection<void (SenderType::*)(), bool (ReceiverType::*)()>,
|
|
Connection<void (SenderType::*)() const, bool (ReceiverType::*)()>,
|
|
Connection<void (SenderType::*)(), void (ReceiverType::*)()>,
|
|
Connection<void (SenderType::*)() const, void (ReceiverType::*)()>>;
|
|
|
|
template <typename SenderType, typename ReceiverType>
|
|
using ConnectionList = QList<ConnectionVariant<SenderType, ReceiverType>>;
|
|
|
|
template <typename Sender, typename Receiver>
|
|
using LinkList = QList<Link<Sender, Receiver>>;
|
|
|
|
// Derivatives
|
|
|
|
using Repository = DataRepositorySignals;
|
|
using Model = BaseSqlTableModel;
|
|
using Finder = EntityFinderWidget;
|
|
|
|
// WARNING: Use only producing types in cpp file
|
|
|
|
// Producing types of Repository and Model
|
|
using RMLink = QPair<Repository *, Model *>;
|
|
using RMConnection = ConnectionVariant<Repository, Model>;
|
|
using RMConnectionList = QList<RMConnection>;
|
|
using RMLinkList = QList<RMLink>;
|
|
|
|
// Producing types of Repository and Finder
|
|
using RFLink = QPair<Repository *, Finder *>;
|
|
using RFConnection = ConnectionVariant<Repository, Finder>;
|
|
using RFConnectionList = QList<RFConnection>;
|
|
using RFLinkList = QList<RFLink>;
|
|
|
|
private:
|
|
ModelManager &modelManager_;
|
|
QObject *rootObject_;
|
|
RepositoryManager &repositoryManager_;
|
|
|
|
public:
|
|
ApplicationConnector(QObject *rootObject);
|
|
|
|
bool connect();
|
|
|
|
private:
|
|
template <typename SenderType, typename ReceiverType>
|
|
bool accessible(const Link<SenderType, ReceiverType> &link);
|
|
|
|
template <typename SignalType, typename SlotType, typename SenderType,
|
|
typename ReceiverType>
|
|
bool connect(SenderType *sender, ReceiverType *receiver,
|
|
const ConnectionList<SignalType, SlotType> &connections);
|
|
|
|
template <typename SignalType, typename SlotType, typename SenderType,
|
|
typename ReceiverType>
|
|
bool connect(const LinkList<SenderType, ReceiverType> &links,
|
|
const ConnectionList<SignalType, SlotType> &connections);
|
|
|
|
template <typename SignalType, typename SlotType>
|
|
QString templateString(SignalType signal, SlotType slot, QObject *sender,
|
|
QObject *receiver);
|
|
|
|
private:
|
|
RFConnectionList repositoryToFinderConnections();
|
|
RMConnectionList pairTableConnections();
|
|
RMConnectionList singleTableConnections();
|
|
|
|
RFLinkList flattenLinkList(const QVector<RFLinkList> &linkLists);
|
|
RFLinkList linkRepositoryToFinder(const QString &sender,
|
|
const QString &receiver);
|
|
RMLink linkRepositoryToModel(const QString &sender, const QString &receiver);
|
|
|
|
RFLinkList initializeDeleteCandidates();
|
|
RFLinkList initializeUpdateDeleteCandidates();
|
|
RMLinkList initializeSelfReferenceTableLinks();
|
|
RMLinkList initializeTablePairLinks();
|
|
|
|
bool connectDeleteRFLinks();
|
|
bool connectSelfReferenceTableLinks();
|
|
bool connectTablePairLinks();
|
|
bool connectUpdateDeleteRFLinks();
|
|
|
|
private:
|
|
QString getAddress(const QObject *object);
|
|
|
|
QString getMetaClassName(const QMetaObject *meta);
|
|
|
|
QString getMethodSignature(const QMetaObject *meta, const char *methodType,
|
|
bool isSignal);
|
|
};
|
|
|
|
template <typename SenderType, typename ReceiverType>
|
|
bool ApplicationConnector::accessible(
|
|
const Link<SenderType, ReceiverType> &link) {
|
|
return bool(link.first && link.second);
|
|
}
|
|
|
|
template <typename SignalType, typename SlotType, typename SenderType,
|
|
typename ReceiverType>
|
|
bool ApplicationConnector::connect(
|
|
const LinkList<SenderType, ReceiverType> &links,
|
|
const ConnectionList<SignalType, SlotType> &connections) {
|
|
for (const Link<SenderType, ReceiverType> ¤tLink : links) {
|
|
qInfo() << "Connecting link: Index of ConnectionList:"
|
|
<< links.indexOf(currentLink);
|
|
|
|
if (!accessible(currentLink)) {
|
|
qWarning() << "Link is not accessible: Index of ConnectionList:"
|
|
<< links.indexOf(currentLink);
|
|
continue;
|
|
}
|
|
|
|
SenderType *sender = currentLink.first;
|
|
ReceiverType *receiver = currentLink.second;
|
|
|
|
if (!connect(sender, receiver, connections)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename SignalType, typename SlotType, typename SenderType,
|
|
typename ReceiverType>
|
|
bool ApplicationConnector::connect(
|
|
SenderType *sender, ReceiverType *receiver,
|
|
const ConnectionList<SignalType, SlotType> &connections) {
|
|
|
|
// WARNING: "auto" keyword is necessary
|
|
auto handler = [&](const auto ¤tLink) -> bool {
|
|
auto &[signal, slot] = currentLink;
|
|
|
|
bool connected = QObject::connect(sender, signal, receiver, slot);
|
|
if (!connected) {
|
|
qWarning().noquote() << "Failed to connect signal to slot:"
|
|
<< templateString(signal, slot, sender, receiver);
|
|
} else {
|
|
qInfo().noquote() << "Connected signal to slot:"
|
|
<< templateString(signal, slot, sender, receiver);
|
|
}
|
|
|
|
return connected;
|
|
};
|
|
|
|
for (const ConnectionVariant<SenderType, ReceiverType> ¤tConnection :
|
|
connections) {
|
|
bool connected = std::visit(handler, currentConnection);
|
|
if (!connected) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename SignalType, typename SlotType>
|
|
QString ApplicationConnector::templateString(SignalType signal, SlotType slot,
|
|
QObject *sender,
|
|
QObject *receiver) {
|
|
const QMetaObject *senderMeta = sender ? sender->metaObject() : nullptr;
|
|
const QMetaObject *receiverMeta = receiver ? receiver->metaObject() : nullptr;
|
|
|
|
auto width = [](int index) {
|
|
switch (index) {
|
|
case 0:
|
|
return 10;
|
|
case 1:
|
|
return -30;
|
|
default:
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
QString billetTA = QString("\n\t|%0: Type: %1 Address: 0x%2");
|
|
QString billetTAN = billetTA + QString(" Name: \"%3\"");
|
|
QString result;
|
|
|
|
QString signalT = getMethodSignature(senderMeta, typeid(signal).name(), true);
|
|
QString signalA = senderMeta ? getAddress(sender) : "null";
|
|
|
|
result +=
|
|
billetTA.arg("Signal", width(0)).arg(signalT, width(1)).arg(signalA);
|
|
|
|
QString slotT = getMethodSignature(receiverMeta, typeid(slot).name(), false);
|
|
QString slotA = receiverMeta ? getAddress(receiver) : "null";
|
|
|
|
result += billetTA.arg("Slot", width(0)).arg(slotT, width(1)).arg(slotA);
|
|
|
|
QString senderT = getMetaClassName(senderMeta);
|
|
QString senderA = getAddress(sender);
|
|
QString senderN = sender->objectName();
|
|
|
|
result += billetTAN.arg("Sender", width(0))
|
|
.arg(senderT, width(1))
|
|
.arg(senderA)
|
|
.arg(senderN);
|
|
|
|
QString receiverT = getMetaClassName(receiverMeta);
|
|
QString receiverA = getAddress(receiver);
|
|
QString receiverN = receiver->objectName();
|
|
|
|
result += billetTAN.arg("Receiver", width(0))
|
|
.arg(receiverT, width(1))
|
|
.arg(receiverA)
|
|
.arg(receiverN);
|
|
|
|
return result;
|
|
}
|
|
|
|
#endif // APPLICATION_CONNECTOR_H
|