Files

239 lines
7.6 KiB
C++
Raw Permalink Normal View History

2026-07-12 14:34:52 +04:00
#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> &currentLink : 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 &currentLink) -> 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> &currentConnection :
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