File indexing completed on 2025-01-05 05:23:46

0001 /*
0002     This file is part of the Okteta Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2009, 2012 Alex Richardson <alex.richardson@gmx.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "structureaddremovewidget.hpp"
0010 
0011 #include "../structuresmanager.hpp"
0012 #include "../structuredefinitionfile.hpp"
0013 #include "structureenabledlist.hpp"
0014 #include <structureslogging.hpp>
0015 // KF
0016 #include <KLocalizedString>
0017 // Qt
0018 #include <QPushButton>
0019 #include <QLabel>
0020 #include <QHBoxLayout>
0021 #include <QVBoxLayout>
0022 #include <QTreeWidget>
0023 #include <QTreeWidgetItem>
0024 #include <QRegularExpression>
0025 // Std
0026 #include <utility>
0027 
0028 using namespace Kasten;
0029 
0030 namespace {
0031 
0032 enum EntryRoles {
0033     OnlyOneRole = Qt::UserRole,
0034 };
0035 constexpr int OnlyOneRowColumn = 0;
0036 
0037 }
0038 
0039 StructureAddRemoveWidget::StructureAddRemoveWidget(const QMap<QString, Kasten::StructureDefinitionFile*>& structureDefs,
0040                                                    const StructureEnabledList& enabledList,
0041                                                    QWidget* parent)
0042     : QWidget(parent)
0043 {
0044     auto* baseLayout = new QHBoxLayout();
0045     baseLayout->setContentsMargins(0, 0, 0, 0);
0046 
0047     auto* tree1Layout = new QVBoxLayout();
0048     mTree1Label = new QLabel(i18nc("@info:label", "Installed structures:"), this);
0049     tree1Layout->addWidget(mTree1Label);
0050     mTreeAvailable = new QTreeWidget(this);
0051     mTreeAvailable->setHeaderHidden(true);
0052     mTreeAvailable->setSelectionMode(QAbstractItemView::ExtendedSelection);
0053     mTreeAvailable->setColumnCount(2);
0054     mTreeAvailable->setColumnHidden(1, true);
0055     tree1Layout->addWidget(mTreeAvailable);
0056 
0057     auto* tree2Layout = new QVBoxLayout();
0058     mTree2Label = new QLabel(i18nc("@info:label", "Used structures:"), this);
0059     tree2Layout->addWidget(mTree2Label);
0060     mTreeSelected = new QTreeWidget(this);
0061     mTreeSelected->setHeaderHidden(true);
0062     mTreeSelected->setSelectionMode(QAbstractItemView::ExtendedSelection);
0063     mTreeSelected->setColumnCount(2);
0064     mTreeSelected->setColumnHidden(1, true);
0065     tree2Layout->addWidget(mTreeSelected);
0066 
0067     auto* leftRightLayout = new QVBoxLayout();
0068     leftRightLayout->addStretch();
0069     mRightButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-right")), QString(), this);
0070     leftRightLayout->addWidget(mRightButton);
0071     mLeftButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-left")), QString(), this);
0072     leftRightLayout->addWidget(mLeftButton);
0073     leftRightLayout->addStretch();
0074 
0075     auto* upDownLayout = new QVBoxLayout();
0076     upDownLayout->addStretch();
0077     mUpButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-up")), QString(), this);
0078     upDownLayout->addWidget(mUpButton);
0079     mDownButton = new QPushButton(QIcon::fromTheme(QStringLiteral("arrow-down")), QString(), this);
0080     upDownLayout->addWidget(mDownButton);
0081     upDownLayout->addStretch();
0082 
0083     baseLayout->addLayout(tree1Layout);
0084     baseLayout->addLayout(leftRightLayout);
0085     baseLayout->addLayout(tree2Layout);
0086     baseLayout->addLayout(upDownLayout);
0087     setLayout(baseLayout);
0088 
0089     connect(mLeftButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveLeft);
0090     connect(mRightButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveRight);
0091     connect(mUpButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveUp);
0092     connect(mDownButton, &QPushButton::pressed, this, &StructureAddRemoveWidget::moveDown);
0093 
0094     buildAvailableList(structureDefs, enabledList);
0095 
0096     // already loaded defs:
0097     for (const StructureEnabledData& enabledData : enabledList) {
0098         if (enabledData.structure == QLatin1String("*")) {
0099             // add all of them
0100             StructureDefinitionFile* def = structureDefs.value(enabledData.id);
0101             if (!def) {
0102                 continue;
0103             }
0104             const auto structureNames = def->structureNames();
0105             const bool isOnlyOne = (structureNames.size() == 1);
0106             for (const QString& structure : structureNames) {
0107                 appendEnabledStructureItem(enabledData.id, structure, isOnlyOne);
0108             }
0109         } else {
0110             appendEnabledStructureItem(enabledData.id, enabledData.structure, false);
0111         }
0112     }
0113 }
0114 
0115 StructureAddRemoveWidget::~StructureAddRemoveWidget() = default;
0116 
0117 QStringList StructureAddRemoveWidget::values() const
0118 {
0119     const QString expressionTemplate = QStringLiteral("\'%1\':\'%2\'");
0120 
0121     QStringList enabledStructures;
0122     const int topLevelItemCount = mTreeSelected->topLevelItemCount();
0123     enabledStructures.reserve(topLevelItemCount);
0124     for (int i = 0; i < topLevelItemCount; ++i) {
0125         QTreeWidgetItem* item = mTreeSelected->topLevelItem(i);
0126         const bool isOnlyOne = item->data(OnlyOneRowColumn, ::OnlyOneRole).toBool();
0127         const QString id = item->text(1);
0128         const QString structure = isOnlyOne ? QStringLiteral("*") : item->text(0);
0129         enabledStructures.append(expressionTemplate.arg(id, structure));
0130     }
0131 
0132     return enabledStructures;
0133 }
0134 
0135 void StructureAddRemoveWidget::buildAvailableList(const QMap<QString, Kasten::StructureDefinitionFile*>& structureDefs,
0136                                                   const StructureEnabledList& enabledList)
0137 {
0138     QList<QTreeWidgetItem*> availableItems;
0139     for (StructureDefinitionFile* def : structureDefs) {
0140         if (!def->isValid()) {
0141             continue;
0142         }
0143         const QString id = def->metaData().id();
0144         if (!enabledList.isEnabled(id)) {
0145            continue;
0146         }
0147         auto* item = new QTreeWidgetItem(mTreeAvailable, QStringList { def->metaData().id(), id });
0148         const auto structureNames = def->structureNames();
0149         for (const QString& name : structureNames) {
0150             auto* subItem = new QTreeWidgetItem(item, QStringList { name, id });
0151             item->addChild(subItem);
0152         }
0153 
0154         availableItems.append(item);
0155     }
0156 
0157     mTreeAvailable->addTopLevelItems(availableItems);
0158 
0159 }
0160 
0161 void StructureAddRemoveWidget::appendEnabledStructureItem(const QString& id, const QString& structure,
0162                                                           bool isOnlyOne)
0163 {
0164     auto* item = new QTreeWidgetItem(mTreeSelected, QStringList { structure, id });
0165     item->setData(OnlyOneRowColumn, ::OnlyOneRole, isOnlyOne);
0166     mTreeSelected->addTopLevelItem(item);
0167 }
0168 
0169 void StructureAddRemoveWidget::moveLeft()
0170 {
0171     const QList<QTreeWidgetItem*> selected = mTreeSelected->selectedItems();
0172     for (QTreeWidgetItem* item : selected) {
0173         delete mTreeSelected->takeTopLevelItem(
0174             mTreeSelected->indexOfTopLevelItem(item));
0175     }
0176 }
0177 
0178 void StructureAddRemoveWidget::moveRight()
0179 {
0180     const QList<QTreeWidgetItem*> selected = mTreeAvailable->selectedItems();
0181     for (const QTreeWidgetItem* item : selected) {
0182         if (!item->parent()) {
0183             continue;     // maybe sometime add all subitems
0184         }
0185         const bool isOnlyOne = item->data(OnlyOneRowColumn, ::OnlyOneRole).toBool();
0186         const QString id = item->text(1);
0187         const QString structure = item->text(0);
0188         appendEnabledStructureItem(id, structure, isOnlyOne);
0189     }
0190 }
0191 
0192 void StructureAddRemoveWidget::moveUp()
0193 {
0194     const QList<QTreeWidgetItem*> selected = mTreeSelected->selectedItems();
0195     int firstIndex = -1;
0196     for (QTreeWidgetItem* item : selected) {
0197         int idx = mTreeSelected->indexOfTopLevelItem(item);
0198         int newIdx = qMax(0, idx - 1);
0199         mTreeSelected->insertTopLevelItem(newIdx,
0200                                           mTreeSelected->takeTopLevelItem(idx));
0201         // only first index
0202         firstIndex = firstIndex == -1 ? newIdx : firstIndex;
0203     }
0204 
0205     if (firstIndex != -1) {
0206         mTreeSelected->setCurrentItem(mTreeSelected->topLevelItem(firstIndex));
0207     }
0208 }
0209 
0210 void StructureAddRemoveWidget::moveDown()
0211 {
0212     const QList<QTreeWidgetItem*> selected = mTreeSelected->selectedItems();
0213     int firstIndex = -1;
0214     int maxItmCount = mTreeSelected->topLevelItemCount();
0215     for (QTreeWidgetItem* item : selected) {
0216         int idx = mTreeSelected->indexOfTopLevelItem(item);
0217         int newIdx = qMin(idx + 1, maxItmCount - 1);
0218         mTreeSelected->insertTopLevelItem(newIdx,
0219                                           mTreeSelected->takeTopLevelItem(idx));
0220         // only first index
0221         firstIndex = firstIndex == -1 ? newIdx : firstIndex;
0222     }
0223 
0224     if (firstIndex != -1) {
0225         mTreeSelected->setCurrentItem(mTreeSelected->topLevelItem(firstIndex));
0226     }
0227 }
0228 
0229 #include "moc_structureaddremovewidget.cpp"