#ifndef APPLICATION_CONNECTOR_H #define APPLICATION_CONNECTOR_H #include #include #include // 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 using Link = QPair; template using Connection = QPair; template using ConnectionVariant = std::variant< Connection, Connection, Connection, Connection>; template using ConnectionList = QList>; template using LinkList = QList>; // 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; using RMConnection = ConnectionVariant; using RMConnectionList = QList; using RMLinkList = QList; // Producing types of Repository and Finder using RFLink = QPair; using RFConnection = ConnectionVariant; using RFConnectionList = QList; using RFLinkList = QList; private: ModelManager &modelManager_; QObject *rootObject_; RepositoryManager &repositoryManager_; public: ApplicationConnector(QObject *rootObject); bool connect(); private: template bool accessible(const Link &link); template bool connect(SenderType *sender, ReceiverType *receiver, const ConnectionList &connections); template bool connect(const LinkList &links, const ConnectionList &connections); template QString templateString(SignalType signal, SlotType slot, QObject *sender, QObject *receiver); private: RFConnectionList repositoryToFinderConnections(); RMConnectionList pairTableConnections(); RMConnectionList singleTableConnections(); RFLinkList flattenLinkList(const QVector &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 bool ApplicationConnector::accessible( const Link &link) { return bool(link.first && link.second); } template bool ApplicationConnector::connect( const LinkList &links, const ConnectionList &connections) { for (const Link ¤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 bool ApplicationConnector::connect( SenderType *sender, ReceiverType *receiver, const ConnectionList &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 ¤tConnection : connections) { bool connected = std::visit(handler, currentConnection); if (!connected) { return false; } } return true; } template 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