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

0001 // ct_lvtqtc_edge_based_tool.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_lvtldr_lakosiannode.h>
0021 #include <ct_lvtqtc_edge_based_tool.h>
0022 #include <ct_lvtqtc_graphicsview.h>
0023 #include <ct_lvtqtc_lakosentity.h>
0024 #include <ct_lvtshr_functional.h>
0025 
0026 #include <QDebug>
0027 #include <QGraphicsLineItem>
0028 
0029 namespace Codethink::lvtqtc {
0030 
0031 struct EdgeBasedTool::Private {
0032     LakosEntity *fromItem = nullptr;
0033     LakosEntity *toItem = nullptr;
0034 };
0035 
0036 EdgeBasedTool::EdgeBasedTool(const QString& name, const QString& tooltip, const QIcon& icon, GraphicsView *gv):
0037     ITool(name, tooltip, icon, gv), d(std::make_unique<Private>())
0038 {
0039 }
0040 
0041 EdgeBasedTool::~EdgeBasedTool() = default;
0042 
0043 void EdgeBasedTool::activate()
0044 {
0045     Q_EMIT sendMessage(tr("Select the source Element"), KMessageWidget::Information);
0046     ITool::activate();
0047 }
0048 
0049 void EdgeBasedTool::mousePressEvent(QMouseEvent *event)
0050 {
0051     if (event->modifiers()) {
0052         event->setAccepted(false);
0053     }
0054     const auto qItems = graphicsView()->itemsByType<LakosEntity>(event->pos());
0055     if (qItems.empty()) {
0056         event->setAccepted(false);
0057     }
0058 }
0059 
0060 void EdgeBasedTool::mouseReleaseEvent(QMouseEvent *event)
0061 {
0062     Q_UNUSED(event);
0063     const auto qItems = graphicsView()->itemsByType<LakosEntity>(event->pos());
0064     if (qItems.empty()) {
0065         event->setAccepted(false);
0066         return;
0067     }
0068 
0069     if (!d->fromItem) {
0070         d->fromItem = qItems.at(0);
0071         Q_EMIT sendMessage(tr("Source element: <strong>%1</strong>, Select the target Element")
0072                                .arg(QString::fromStdString(d->fromItem->name())),
0073                            KMessageWidget::Information);
0074         return;
0075     }
0076 
0077     d->toItem = qItems.at(0);
0078     if (!d->toItem) {
0079         return;
0080     }
0081 
0082     if (d->toItem->hasRelationshipWith(d->fromItem) || d->fromItem->hasRelationshipWith(d->toItem)) {
0083         Q_EMIT sendMessage(
0084             tr("You can't connect %1 to %2, they already have a connection.")
0085                 .arg(QString::fromStdString(d->fromItem->name()), QString::fromStdString(d->toItem->name())),
0086             KMessageWidget::Error);
0087         deactivate();
0088         return;
0089     }
0090 
0091     if (d->fromItem && d->toItem) {
0092         if (run(d->fromItem, d->toItem)) {
0093             Q_EMIT sendMessage(QString(), KMessageWidget::Information);
0094         }
0095         deactivate();
0096     }
0097 }
0098 
0099 void EdgeBasedTool::deactivate()
0100 {
0101     d->fromItem = nullptr;
0102     d->toItem = nullptr;
0103 
0104     ITool::deactivate();
0105 }
0106 
0107 std::vector<std::pair<LakosEntity *, LakosEntity *>> EdgeBasedTool::calculateHierarchy(LakosEntity *source,
0108                                                                                        LakosEntity *target)
0109 {
0110     qCDebug(LogTool) << "Calculating hierarchy for" << QString::fromStdString(source->name()) << "and"
0111                      << QString::fromStdString(target->name());
0112     std::vector<std::pair<LakosEntity *, LakosEntity *>> ret;
0113     while (source->parentItem() && target->parentItem()) {
0114         source = qgraphicsitem_cast<LakosEntity *>(source->parentItem());
0115         target = qgraphicsitem_cast<LakosEntity *>(target->parentItem());
0116 
0117         const auto& iSource = source->internalNode();
0118         const auto& iTarget = target->internalNode();
0119 
0120         if (iSource == iTarget) {
0121             // Early return if found a common ancestor
0122             break;
0123         }
0124 
0125         if (!iSource->hasProvider(iTarget)) {
0126             ret.emplace_back(std::make_pair(source, target));
0127         }
0128     }
0129 
0130     // we need to add the items in order, first to the toplevel element
0131     // that lacks a connection, to the inner element.
0132     std::reverse(ret.begin(), ret.end());
0133 
0134     return ret;
0135 }
0136 } // namespace Codethink::lvtqtc