File indexing completed on 2024-05-19 05:41:57

0001 // ct_lvtcgn_app_adapter.cpp                              -*-C++-*-
0002 
0003 /*
0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk>
0005 // SPDX-License-Identifier: Apache-2.0
0006 //
0007 // Licensed under the Apache License, Version 2.0 (the "License");
0008 // you may not use this file except in compliance with the License.
0009 // You may obtain a copy of the License at
0010 //
0011 //     http://www.apache.org/licenses/LICENSE-2.0
0012 //
0013 // Unless required by applicable law or agreed to in writing, software
0014 // distributed under the License is distributed on an "AS IS" BASIS,
0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016 // See the License for the specific language governing permissions and
0017 // limitations under the License.
0018 */
0019 
0020 #include <ct_lvtcgn_app_adapter.h>
0021 #include <ct_lvtcgn_codegendialog.h>
0022 #include <ct_lvtcgn_generatecode.h>
0023 
0024 #include <ct_lvtldr_lakosiannode.h>
0025 #include <ct_lvtldr_nodestorage.h>
0026 
0027 #include <preferences.h>
0028 
0029 using namespace Codethink::lvtcgn::mdl;
0030 using namespace Codethink::lvtcgn::gui;
0031 using namespace Codethink::lvtldr;
0032 using namespace Codethink::lvtshr;
0033 
0034 namespace {
0035 bool shouldDefaultSelectForCodegen(LakosianNode& node)
0036 {
0037     // External dependencies (Within non-lakosian group) are disabled by default
0038     if (node.name() == "non-lakosian group") {
0039         return false;
0040     }
0041     auto *parentNode = &node;
0042     while (parentNode->parent()) {
0043         parentNode = parentNode->parent();
0044         if (parentNode->name() == "non-lakosian group") {
0045             return false;
0046         }
0047     }
0048 
0049     return true;
0050 }
0051 } // namespace
0052 
0053 namespace Codethink::lvtcgn::app {
0054 
0055 WrappedLakosianNode::WrappedLakosianNode(NodeStorageDataProvider& dataProvider,
0056                                          LakosianNode *node,
0057                                          bool isSelectedForCodegen):
0058     dataProvider(dataProvider), node(node), isSelectedForCodegen(isSelectedForCodegen)
0059 {
0060 }
0061 
0062 WrappedLakosianNode::~WrappedLakosianNode() = default;
0063 
0064 std::string WrappedLakosianNode::name() const
0065 {
0066     return node->name();
0067 }
0068 
0069 std::string WrappedLakosianNode::type() const
0070 {
0071     std::string type = "Unknown";
0072     if (node->type() == DiagramType::ComponentType) {
0073         type = "Component";
0074     }
0075     if (node->type() == DiagramType::PackageType && node->parent() != nullptr) {
0076         type = "Package";
0077     }
0078     if (node->type() == DiagramType::PackageType && node->parent() == nullptr) {
0079         // If there's no parent, the node may be a package or a package group:
0080         auto const& children = node->children();
0081         if (children.empty()) {
0082             // (1) If there are no children, assume package.
0083             type = "Package";
0084         } else if (children.at(0)->type() == DiagramType::PackageType) {
0085             // (2) If any child is a package, assume package groups
0086             type = "PackageGroup";
0087         } else if (children.at(0)->type() == DiagramType::ComponentType) {
0088             // (3) If any child is a component, assume package
0089             type = "Package";
0090         }
0091     }
0092     return type;
0093 }
0094 
0095 std::optional<std::reference_wrapper<IPhysicalEntityInfo>> WrappedLakosianNode::parent() const
0096 {
0097     if (!node->parent()) {
0098         return std::nullopt;
0099     }
0100     return dataProvider.getWrappedNode(node->parent());
0101 }
0102 
0103 std::vector<std::reference_wrapper<IPhysicalEntityInfo>> WrappedLakosianNode::children() const
0104 {
0105     auto wrappedVec = std::vector<std::reference_wrapper<IPhysicalEntityInfo>>{};
0106     for (auto *e : node->children()) {
0107         if (e->type() == DiagramType::ComponentType || e->type() == DiagramType::PackageType) {
0108             wrappedVec.push_back(dataProvider.getWrappedNode(e));
0109         }
0110     }
0111     return wrappedVec;
0112 }
0113 
0114 std::vector<std::reference_wrapper<IPhysicalEntityInfo>> WrappedLakosianNode::fwdDependencies() const
0115 {
0116     auto wrappedVec = std::vector<std::reference_wrapper<IPhysicalEntityInfo>>{};
0117     for (auto const& edge : node->providers()) {
0118         auto *e = edge.other();
0119         if (e->type() == DiagramType::ComponentType || e->type() == DiagramType::PackageType) {
0120             wrappedVec.push_back(dataProvider.getWrappedNode(e));
0121         }
0122     }
0123     return wrappedVec;
0124 }
0125 
0126 bool WrappedLakosianNode::selectedForCodeGeneration() const
0127 {
0128     return isSelectedForCodegen;
0129 }
0130 
0131 void WrappedLakosianNode::setSelectedForCodeGeneration(bool value)
0132 {
0133     isSelectedForCodegen = value;
0134 }
0135 
0136 NodeStorageDataProvider::NodeStorageDataProvider(Codethink::lvtldr::NodeStorage& sharedNodeStorage):
0137     ns(sharedNodeStorage)
0138 {
0139 }
0140 
0141 NodeStorageDataProvider::~NodeStorageDataProvider() = default;
0142 
0143 std::reference_wrapper<IPhysicalEntityInfo> NodeStorageDataProvider::getWrappedNode(LakosianNode *node)
0144 {
0145     if (nodeToInfo.find(node) == nodeToInfo.end()) {
0146         nodeToInfo.insert(
0147             {node, std::make_unique<WrappedLakosianNode>(*this, node, shouldDefaultSelectForCodegen(*node))});
0148     }
0149     return *nodeToInfo.at(node);
0150 }
0151 
0152 std::vector<std::reference_wrapper<IPhysicalEntityInfo>> NodeStorageDataProvider::topLevelEntities()
0153 {
0154     std::vector<std::reference_wrapper<IPhysicalEntityInfo>> refVec;
0155     for (auto *topLevelNode : ns.getTopLevelPackages()) {
0156         refVec.emplace_back(getWrappedNode(topLevelNode).get());
0157     }
0158     return refVec;
0159 }
0160 
0161 int NodeStorageDataProvider::numberOfPhysicalEntities() const
0162 {
0163     // Count package groups
0164     auto topLvlPkgs = ns.getTopLevelPackages();
0165     auto counter = topLvlPkgs.size();
0166     for (auto *pkgGrp : topLvlPkgs) {
0167         // Count packages
0168         counter += pkgGrp->children().size();
0169         for (auto *pkg : pkgGrp->children()) {
0170             // Count components
0171             counter += pkg->children().size();
0172         }
0173     }
0174     return int(counter);
0175 }
0176 
0177 void CodegenAppAdapter::run(QWidget *parent, Codethink::lvtldr::NodeStorage& sharedNodeStorage)
0178 {
0179     auto dataProvider = NodeStorageDataProvider{sharedNodeStorage};
0180     auto dialog = CodeGenerationDialog{dataProvider, nullptr, parent};
0181 
0182     dialog.setOutputDir(Preferences::lastOutputDir());
0183 
0184     dialog.exec();
0185 
0186     Preferences::setLastOutputDir(dialog.outputDir());
0187 }
0188 
0189 } // namespace Codethink::lvtcgn::app