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

0001 // ct_lvtqtc_inspect_dependency_window.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_lvtprj_projectfile.h>
0021 #include <ct_lvtqtc_inspect_dependency_window.h>
0022 
0023 #include <QDebug>
0024 #include <QDesktopServices>
0025 #include <QDialog>
0026 #include <QFileInfo>
0027 #include <QGraphicsScene>
0028 #include <QHeaderView>
0029 #include <QLabel>
0030 #include <QLayout>
0031 #include <QLine>
0032 #include <QMessageBox>
0033 #include <QUrl>
0034 
0035 Q_DECLARE_METATYPE(Codethink::lvtldr::LakosianNode *)
0036 
0037 namespace Codethink::lvtqtc {
0038 
0039 InspectDependencyWindow::InspectDependencyWindow(lvtprj::ProjectFile const& projectFile,
0040                                                  LakosRelation const& r,
0041                                                  QDialog *parent):
0042     QDialog(parent), d_lakosRelation(r), d_projectFile(projectFile)
0043 {
0044     setWindowModality(Qt::ApplicationModal);
0045     setWindowTitle(tr("Dependency inspector"));
0046     setMinimumWidth(600);
0047     setMinimumHeight(400);
0048 
0049     setupUi();
0050 
0051     d_contentsTable->setContextMenuPolicy(Qt::CustomContextMenu);
0052     connect(d_contentsTable, &QTableWidget::customContextMenuRequested, this, [this](const QPoint& pos) {
0053         QTableWidgetItem *item = d_contentsTable->itemAt(pos);
0054         if (!item) {
0055             return;
0056         }
0057 
0058         auto *menu = item->data(MenuRole).value<QMenu *>();
0059         if (!menu) {
0060             return;
0061         }
0062 
0063         menu->exec(pos);
0064     });
0065     populateContentsTable();
0066 }
0067 
0068 void InspectDependencyWindow::setupUi()
0069 {
0070     auto *from = d_lakosRelation.from();
0071     auto *to = d_lakosRelation.to();
0072     auto *layout = new QVBoxLayout{this};
0073     auto *titleLabel = new QLabel{this};
0074     titleLabel->setText(tr("Inspect dependencies from %1 to %2")
0075                             .arg(QString::fromStdString(from->name()), QString::fromStdString(to->name())));
0076     titleLabel->setStyleSheet("font-weight: bold;");
0077 
0078     layout->addWidget(titleLabel);
0079     d_contentsTable = new QTableWidget{this};
0080     d_contentsTable->setColumnCount(2);
0081     d_contentsTable->setHorizontalHeaderLabels({tr("From component"), tr("To component")});
0082 
0083     auto *header = d_contentsTable->horizontalHeader();
0084     header->setMinimumSectionSize(10);
0085     header->setSectionResizeMode(0, QHeaderView::Stretch);
0086     header->setSectionResizeMode(1, QHeaderView::Stretch);
0087     layout->addWidget(d_contentsTable);
0088 
0089     // make the scrollbar touch the window frame on the right.
0090     layout->setSpacing(0);
0091     layout->setContentsMargins(6, 6, 0, 6);
0092     setLayout(layout);
0093 }
0094 
0095 void InspectDependencyWindow::openFile(lvtldr::LakosianNode *pkg, lvtldr::LakosianNode *component, const QString& ext)
0096 {
0097     auto prefix = d_projectFile.sourceCodePath();
0098     auto filepath = [&]() {
0099         if (pkg->parent()) {
0100             return QString::fromStdString(
0101                        (prefix / "groups" / pkg->parent()->name() / pkg->name() / component->name()).string())
0102                 + ext;
0103         }
0104         return QString::fromStdString((prefix / "standalones" / pkg->name() / component->name()).string()) + ext;
0105     }();
0106 
0107     if (!QFileInfo::exists(filepath) || !QDesktopServices::openUrl(QUrl::fromLocalFile(filepath))) {
0108         showFileNotFoundWarning(filepath);
0109     }
0110 }
0111 
0112 void InspectDependencyWindow::showFileNotFoundWarning(QString const& filepath) const
0113 {
0114     QMessageBox::warning(nullptr, tr("Warning"), tr("File not found: %1").arg(filepath));
0115 }
0116 
0117 void InspectDependencyWindow::populateContentsTable()
0118 {
0119     auto *from = d_lakosRelation.from();
0120     auto *to = d_lakosRelation.to();
0121 
0122     auto createContentActionButton = [&](lvtldr::LakosianNode *fromChild) -> QMenu * {
0123         auto *menu = new QMenu();
0124         auto *open_source = menu->addAction(tr("Open source"));
0125         connect(open_source, &QAction::triggered, this, [this, from, fromChild] {
0126             openFile(from->internalNode(), fromChild, ".cpp");
0127         });
0128 
0129         auto *open_header = menu->addAction(tr("Open header"));
0130         connect(open_header, &QAction::triggered, this, [this, from, fromChild] {
0131             openFile(from->internalNode(), fromChild, ".h");
0132         });
0133 
0134         auto *open_test = menu->addAction(tr("Open test"));
0135         connect(open_test, &QAction::triggered, this, [this, from, fromChild] {
0136             openFile(from->internalNode(), fromChild, ".t.cpp");
0137         });
0138         return menu;
0139     };
0140 
0141     for (auto const& fromChild : from->internalNode()->children()) {
0142         for (auto const& dep : fromChild->providers()) {
0143             if (dep.other()->parent() == to->internalNode()) {
0144                 auto const& toChild = dep.other();
0145                 auto *fromItem = new QTableWidgetItem();
0146                 fromItem->setText(QString::fromStdString(fromChild->name()));
0147                 fromItem->setFlags(Qt::ItemFlag::ItemIsEnabled);
0148                 auto *toItem = new QTableWidgetItem();
0149                 toItem->setText(QString::fromStdString(toChild->name()));
0150                 toItem->setFlags(Qt::ItemFlag::ItemIsEnabled);
0151 
0152                 auto i = d_contentsTable->rowCount();
0153                 d_contentsTable->insertRow(i);
0154                 d_contentsTable->setItem(i, 0, fromItem);
0155                 d_contentsTable->setItem(i, 1, toItem);
0156                 fromItem->setData(MenuRole, QVariant::fromValue(createContentActionButton(fromChild)));
0157             }
0158         }
0159     }
0160 }
0161 
0162 } // namespace Codethink::lvtqtc