File indexing completed on 2024-05-19 05:42:22

0001 // ct_lvtqtw_tool_add_package.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_logical_entity.h>
0021 
0022 #include <ct_lvtqtc_componententity.h>
0023 #include <ct_lvtqtc_graphicsscene.h>
0024 #include <ct_lvtqtc_graphicsview.h>
0025 #include <ct_lvtqtc_inputdialog.h>
0026 #include <ct_lvtqtc_logicalentity.h>
0027 #include <ct_lvtqtc_packageentity.h>
0028 #include <ct_lvtqtc_undo_add_logicalentity.h>
0029 
0030 #include <ct_lvtqtc_util.h>
0031 
0032 #include <ct_lvtldr_lakosiannode.h>
0033 #include <ct_lvtldr_nodestorage.h>
0034 #include <ct_lvtqtc_iconhelpers.h>
0035 #include <ct_lvtshr_functional.h>
0036 
0037 #include <QApplication>
0038 #include <QDebug>
0039 #include <QInputDialog>
0040 #include <QMessageBox>
0041 
0042 #include <preferences.h>
0043 
0044 using namespace Codethink::lvtldr;
0045 using namespace Codethink::lvtshr;
0046 
0047 namespace Codethink::lvtqtc {
0048 
0049 struct ToolAddLogicalEntity::Private {
0050     NodeStorage& nodeStorage;
0051 
0052     explicit Private(NodeStorage& nodeStorage): nodeStorage(nodeStorage)
0053     {
0054     }
0055 };
0056 
0057 ToolAddLogicalEntity::ToolAddLogicalEntity(GraphicsView *gv, NodeStorage& nodeStorage):
0058     BaseAddEntityTool(tr("Logical Entity"),
0059                       tr("Creates a Logical Entity (such as classes or structs)"),
0060                       IconHelpers::iconFrom(":/icons/class"),
0061                       gv),
0062     d(std::make_unique<Private>(nodeStorage))
0063 {
0064     auto *inputDataDialog = inputDialog();
0065     inputDataDialog->addTextField("name", tr("Name:"));
0066     inputDataDialog->addComboBoxField("kind", tr("Kind:"), {"Class", "Enum", "Struct", "TypeAlias", "Union"});
0067     inputDataDialog->finish();
0068 }
0069 
0070 ToolAddLogicalEntity::~ToolAddLogicalEntity() = default;
0071 
0072 template<typename T>
0073 cpp::result<void, InvalidLogicalEntityError>
0074 checkNameError(bool hasParent, const std::string& name, const std::string& parentName)
0075 {
0076     return T::checkName(hasParent, name, parentName);
0077 }
0078 
0079 void ToolAddLogicalEntity::activate()
0080 {
0081     Q_EMIT sendMessage(tr("Click on a Component, Class or Struct to add a new Logical Entity"),
0082                        KMessageWidget::Information);
0083     BaseAddEntityTool::activate();
0084 }
0085 
0086 void ToolAddLogicalEntity::mousePressEvent(QMouseEvent *event)
0087 {
0088     qCDebug(LogTool) << name() << "Mouse Press Event";
0089 
0090     using Codethink::lvtshr::ScopeExit;
0091     ScopeExit _([&]() {
0092         deactivate();
0093     });
0094 
0095     auto *parentView = [&]() -> LakosEntity * {
0096         auto *parentClass = graphicsView()->itemByTypeAt<LogicalEntity>(event->pos());
0097         if (parentClass != nullptr) {
0098             return parentClass;
0099         }
0100         return graphicsView()->itemByTypeAt<ComponentEntity>(event->pos());
0101     }();
0102 
0103     if (!parentView) {
0104         Q_EMIT sendMessage(
0105             tr("This is not a valid parent for a user defined type. Parent must be a 'Component', a 'Class' or a "
0106                "'Struct'."),
0107             KMessageWidget::Error);
0108         return;
0109     }
0110 
0111     if (m_nameDialog->exec() == QDialog::Rejected) {
0112         return;
0113     }
0114     assert(parentView);
0115 
0116     auto *parent = parentView->internalNode();
0117     auto parentName = parent->name();
0118     auto name = std::any_cast<QString>(m_nameDialog->fieldValue("name")).toStdString();
0119     auto qualifiedName = parentName + "::" + name;
0120 
0121     auto kindInput = std::any_cast<QString>(m_nameDialog->fieldValue("kind"));
0122     auto kind = ([&kindInput]() {
0123         if (kindInput == "Class") {
0124             return UDTKind::Class;
0125         }
0126         if (kindInput == "Enum") {
0127             return UDTKind::Enum;
0128         }
0129         if (kindInput == "Struct") {
0130             return UDTKind::Struct;
0131         }
0132         if (kindInput == "TypeAlias") {
0133             return UDTKind::TypeAlias;
0134         }
0135         if (kindInput == "Union") {
0136             return UDTKind::Union;
0137         }
0138         return UDTKind::Unknown;
0139     })();
0140 
0141     auto result = d->nodeStorage.addLogicalEntity(name, qualifiedName, parent, kind);
0142     if (result.has_error()) {
0143         using Kind = ErrorAddUDT::Kind;
0144         switch (result.error().kind) {
0145         case Kind::BadParentType: {
0146             Q_EMIT sendMessage(
0147                 tr("This is not a valid parent for a user defined type. Parent must be a 'Component', a 'Class' or a "
0148                    "'Struct'."),
0149                 KMessageWidget::Error);
0150             return;
0151         }
0152         }
0153     }
0154 
0155     // Success, clean the message on the view.
0156     Q_EMIT sendMessage(QString(), KMessageWidget::Information);
0157 
0158     auto *newLogicalEntity = result.value();
0159 
0160     auto *scene = qobject_cast<GraphicsScene *>(graphicsView()->scene());
0161     const QPointF scenePos = graphicsView()->mapToScene(event->pos());
0162     const QPointF itemPos = parentView->mapFromScene(scenePos);
0163     scene->setEntityPos(newLogicalEntity->uid(), itemPos);
0164     scene->updateBoundingRect();
0165     Q_EMIT undoCommandCreated(new UndoAddLogicalEntity(scene,
0166                                                        itemPos,
0167                                                        name,
0168                                                        qualifiedName,
0169                                                        parent->qualifiedName(),
0170                                                        QtcUtil::UndoActionType::e_Add,
0171                                                        d->nodeStorage));
0172 }
0173 
0174 cpp::result<void, InvalidLogicalEntityError>
0175 LogicalEntityNameRules::checkName(bool hasParent, const std::string& name, const std::string& parentName)
0176 {
0177     return {};
0178 }
0179 
0180 } // namespace Codethink::lvtqtc