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