File indexing completed on 2024-05-19 05:42:23
0001 // ct_lvtqtwc_tool_add_physical_dependency.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_lvtqtc_tool_add_physical_dependency.h> 0021 0022 #include <ct_lvtqtc_graphicsscene.h> 0023 #include <ct_lvtqtc_graphicsview.h> 0024 #include <ct_lvtqtc_iconhelpers.h> 0025 #include <ct_lvtqtc_lakosentity.h> 0026 #include <ct_lvtqtc_undo_add_edge.h> 0027 #include <ct_lvtqtc_util.h> 0028 0029 #include <ct_lvtldr_lakosiannode.h> 0030 #include <ct_lvtldr_nodestorage.h> 0031 0032 #include <ct_lvtshr_functional.h> 0033 0034 #include <QDebug> 0035 #include <QGraphicsLineItem> 0036 #include <QMessageBox> 0037 0038 using namespace Codethink::lvtldr; 0039 0040 namespace Codethink::lvtqtc { 0041 0042 struct ToolAddPhysicalDependency::Private { 0043 NodeStorage& nodeStorage; 0044 0045 explicit Private(NodeStorage& nodeStorage): nodeStorage(nodeStorage) 0046 { 0047 } 0048 }; 0049 0050 ToolAddPhysicalDependency::ToolAddPhysicalDependency(GraphicsView *gv, NodeStorage& nodeStorage): 0051 EdgeBasedTool(tr("Physical Dependency"), 0052 tr("Creates a dependency between packages or components"), 0053 IconHelpers::iconFrom(":/icons/new_dependency"), 0054 gv), 0055 d(std::make_unique<Private>(nodeStorage)) 0056 { 0057 } 0058 0059 ToolAddPhysicalDependency::~ToolAddPhysicalDependency() = default; 0060 0061 bool ToolAddPhysicalDependency::run(LakosEntity *fromItem, LakosEntity *toItem) 0062 { 0063 bool needsParentDependencies = false; 0064 { 0065 auto result = d->nodeStorage.addPhysicalDependency(fromItem->internalNode(), toItem->internalNode()); 0066 if (result.has_error()) { 0067 using Kind = ErrorAddPhysicalDependency::Kind; 0068 switch (result.error().kind) { 0069 case Kind::HierarchyLevelMismatch: { 0070 Q_EMIT sendMessage(tr("Cannot create dependency on different hierarchy levels"), KMessageWidget::Error); 0071 return false; 0072 } 0073 case Kind::InvalidType: { 0074 Q_EMIT sendMessage(tr("Only physical entities may be used with this tool"), KMessageWidget::Error); 0075 return false; 0076 } 0077 case Kind::SelfRelation: { 0078 Q_EMIT sendMessage(tr("Cannot create self-dependency"), KMessageWidget::Error); 0079 return false; 0080 } 0081 case Kind::DependencyAlreadyExists: { 0082 Q_EMIT sendMessage(tr("Those elements already have a dependency"), KMessageWidget::Error); 0083 return false; 0084 } 0085 case Kind::MissingParentDependency: { 0086 // do not use the message box in debug mode. assume "yes". 0087 if (property("debug").toBool()) { 0088 needsParentDependencies = true; 0089 } else { 0090 auto ret = QMessageBox::question( 0091 graphicsView(), 0092 tr("Automatically add Dependencies?"), 0093 tr("Parents are not connected, should we add the dependencies automatically?")); 0094 if (ret == QMessageBox::No) { 0095 Q_EMIT sendMessage(tr("We can only add a dependency if the parents are conected"), 0096 KMessageWidget::Error); 0097 return false; 0098 } 0099 needsParentDependencies = true; 0100 } 0101 } 0102 } 0103 } 0104 } 0105 0106 if (needsParentDependencies) { 0107 auto *macro = new QUndoCommand("Multiple Add Edges"); 0108 auto forceAddPhysicalDep = [&](auto const& iFrom, auto const& iTo, auto const& pair) { 0109 // Ignore any errors while FORCING the dependencies 0110 (void) d->nodeStorage.addPhysicalDependency(iFrom, iTo); 0111 new UndoAddEdge(pair.first->qualifiedName(), 0112 pair.second->qualifiedName(), 0113 lvtshr::LakosRelationType::PackageDependency, 0114 QtcUtil::UndoActionType::e_Add, 0115 d->nodeStorage, 0116 macro); 0117 }; 0118 0119 auto hierarchy = calculateHierarchy(fromItem, toItem); 0120 for (const auto& pair : hierarchy) { 0121 const auto& iFrom = pair.first->internalNode(); 0122 const auto& iTo = pair.second->internalNode(); 0123 forceAddPhysicalDep(iFrom, iTo, pair); 0124 } 0125 d->nodeStorage.addPhysicalDependency(fromItem->internalNode(), toItem->internalNode()).expect(""); 0126 new UndoAddEdge(fromItem->qualifiedName(), 0127 toItem->qualifiedName(), 0128 lvtshr::LakosRelationType::PackageDependency, 0129 QtcUtil::UndoActionType::e_Add, 0130 d->nodeStorage, 0131 macro); 0132 Q_EMIT undoCommandCreated(macro); 0133 } else { 0134 // TODO: This should be a Group because of the parent edges. 0135 Q_EMIT undoCommandCreated(new UndoAddEdge(fromItem->qualifiedName(), 0136 toItem->qualifiedName(), 0137 lvtshr::LakosRelationType::PackageDependency, 0138 QtcUtil::UndoActionType::e_Add, 0139 d->nodeStorage)); 0140 } 0141 return true; 0142 } 0143 0144 } // namespace Codethink::lvtqtc