File indexing completed on 2024-05-12 04:39:21

0001 /*
0002     SPDX-FileCopyrightText: 2018 Friedrich W. H. Kossebau <kossebau@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "checklistmodel.h"
0008 
0009 // plugin
0010 #include <checkset.h>
0011 #include <debug.h>
0012 // KF
0013 #include <KLocalizedString>
0014 
0015 
0016 namespace {
0017 
0018 Qt::CheckState checkState(ClangTidy::CheckGroup::EnabledState enabledState)
0019 {
0020     return
0021         (enabledState == ClangTidy::CheckGroup::EnabledInherited) ? Qt::PartiallyChecked :
0022         (enabledState == ClangTidy::CheckGroup::Disabled) ?         Qt::Unchecked :
0023         /* else */                                                  Qt::Checked;
0024 }
0025 
0026 ClangTidy::CheckGroup::EnabledState enabledState(int checkState)
0027 {
0028     return
0029         (checkState == Qt::PartiallyChecked) ? ClangTidy::CheckGroup::EnabledInherited :
0030         (checkState == Qt::Unchecked) ?        ClangTidy::CheckGroup::Disabled  :
0031         /* else */                             ClangTidy::CheckGroup::Enabled;
0032 }
0033 
0034 }
0035 
0036 namespace ClangTidy
0037 {
0038 
0039 CheckListModel::CheckListModel(QObject* parent)
0040     : QAbstractItemModel(parent)
0041 {
0042 }
0043 
0044 CheckListModel::~CheckListModel() = default;
0045 
0046 QVariant CheckListModel::data(const QModelIndex& index, int role) const
0047 {
0048     if (!index.isValid() ||
0049         (index.column() < NameColumnId) || (index.column() > CountColumnId)) {
0050         return QVariant();
0051     }
0052 
0053     auto* checkGroup = static_cast<const CheckGroup*>(index.internalPointer());
0054 
0055     // root?
0056     if (!checkGroup) {
0057         if (index.row() != 0) {
0058             return QVariant();
0059         }
0060         if (role == HasExplicitEnabledStateRole) {
0061             return m_rootCheckGroup->hasSubGroupWithExplicitEnabledState();
0062         } else {
0063             if (index.column() == NameColumnId) {
0064                 if (role == Qt::DisplayRole) {
0065                     return i18nc("@item", "All checks");
0066                 } else
0067                 if (role == Qt::CheckStateRole) {
0068                     return checkState(m_rootCheckGroup->groupEnabledState());
0069                 } else
0070                 if (role == EffectiveEnabledStateRole) {
0071                     return m_rootCheckGroup->effectiveGroupEnabledState();
0072                 }
0073             } else {
0074                 if (role == Qt::DisplayRole) {
0075                     const int enabledChecksCount = m_rootCheckGroup->enabledChecksCount();
0076                     if (enabledChecksCount > 0) {
0077                         return enabledChecksCount;
0078                     }
0079                 } else
0080                 if (role == Qt::TextAlignmentRole) {
0081                     return static_cast<int>(Qt::AlignRight | Qt::AlignVCenter);
0082                 }
0083             }
0084         }
0085     } else {
0086         const int childIndex = index.row();
0087         if (childIndex < 0 || childCount(checkGroup) <= childIndex) {
0088             return QVariant();
0089         }
0090         const int subGroupsCount = checkGroup->subGroups().count();
0091         if (childIndex < subGroupsCount) {
0092             const int subGroupIndex = childIndex;
0093             if (role == HasExplicitEnabledStateRole) {
0094                 auto* subGroup = checkGroup->subGroups().at(subGroupIndex);
0095                 return subGroup->hasSubGroupWithExplicitEnabledState();
0096             } else {
0097                 if (index.column() == NameColumnId) {
0098                     if (role == Qt::DisplayRole) {
0099                         auto* subGroup = checkGroup->subGroups().at(subGroupIndex);
0100                         return subGroup->wildCardText();
0101                     } else
0102                     if (role == Qt::CheckStateRole) {
0103                         auto* subGroup = checkGroup->subGroups().at(subGroupIndex);
0104                         return checkState(subGroup->groupEnabledState());
0105                     } else
0106                     if (role == EffectiveEnabledStateRole) {
0107                         auto* subGroup = checkGroup->subGroups().at(subGroupIndex);
0108                         return subGroup->effectiveGroupEnabledState();
0109                     }
0110                 } else {
0111                     if (role == Qt::DisplayRole) {
0112                         auto* subGroup = checkGroup->subGroups().at(subGroupIndex);
0113                         const int enabledChecksCount = subGroup->enabledChecksCount();
0114                         if (enabledChecksCount > 0) {
0115                             return enabledChecksCount;
0116                         }
0117                     } else
0118                     if (role == Qt::TextAlignmentRole) {
0119                         return static_cast<int>(Qt::AlignRight | Qt::AlignVCenter);
0120                     }
0121                 }
0122             }
0123         } else {
0124             if (index.column() == NameColumnId) {
0125                 const int checkIndex = childIndex - subGroupsCount;
0126                 if (role == Qt::DisplayRole) {
0127                     return checkGroup->checkNames().at(checkIndex);
0128                 } else
0129                 if (role == Qt::CheckStateRole) {
0130                     return checkState(checkGroup->checkEnabledState(checkIndex));
0131                 } else
0132                 if (role == EffectiveEnabledStateRole) {
0133                     return checkGroup->effectiveCheckEnabledState(checkIndex);
0134                 }
0135             }
0136         }
0137     }
0138 
0139     return QVariant();
0140 }
0141 
0142 bool CheckListModel::setData(const QModelIndex& index, const QVariant& value, int role)
0143 {
0144     if (!index.isValid() ||
0145         (role != Qt::CheckStateRole)) {
0146         return false;
0147     }
0148 
0149     const auto enabledState = ::enabledState(value.toInt());
0150     auto* checkGroup = static_cast<CheckGroup*>(index.internalPointer());
0151 
0152     // root?
0153     if (!checkGroup) {
0154         if (index.row() != 0) {
0155             return false;
0156         }
0157 
0158         m_rootCheckGroup->setGroupEnabledState(enabledState);
0159 
0160         m_isDefault = false;
0161         emitSubGroupDataChanged(index);
0162         emit enabledChecksChanged();
0163         return true;
0164     } else {
0165         const int childIndex = index.row();
0166         if (childIndex < 0 || childCount(checkGroup) <= childIndex) {
0167             return false;
0168         }
0169 
0170         CheckGroup* changedSubGroup = nullptr;
0171         const int subGroupsCount = checkGroup->subGroups().count();
0172         if (childIndex < subGroupsCount) {
0173             const int subGroupIndex = childIndex;
0174             auto* subGroup = checkGroup->subGroups().at(subGroupIndex);
0175             const auto oldEffectiveGroupEnabledState = subGroup->effectiveGroupEnabledState();
0176             subGroup->setGroupEnabledState(enabledState);
0177             if (oldEffectiveGroupEnabledState != subGroup->effectiveGroupEnabledState()) {
0178                 changedSubGroup = subGroup;
0179             }
0180         } else {
0181             const int checkIndex = childIndex - subGroupsCount;
0182             checkGroup->setCheckEnabledState(checkIndex, enabledState);
0183         }
0184 
0185         m_isDefault = false;
0186         if (changedSubGroup) {
0187             emitSubGroupDataChanged(index);
0188         } else {
0189             emit dataChanged(index, index, {Qt::CheckStateRole});
0190         }
0191         emit enabledChecksChanged();
0192         return true;
0193     }
0194 
0195     return false;
0196 }
0197 
0198 int CheckListModel::columnCount(const QModelIndex& parent) const
0199 {
0200     Q_UNUSED(parent)
0201     return 2;
0202 }
0203 
0204 int CheckListModel::rowCount(const QModelIndex& parent) const
0205 {
0206     if (!parent.isValid()) {
0207         return m_rootCheckGroup ? 1 : 0;
0208     }
0209 
0210     auto* parentCheckGroup = static_cast<const CheckGroup*>(parent.internalPointer());
0211 
0212     if (!parentCheckGroup) {
0213         return childCount(m_rootCheckGroup.data());
0214     }
0215 
0216     // is subgroup?
0217     const int subGroupIndex = parent.row();
0218     const auto& subGroups = parentCheckGroup->subGroups();
0219     if (0 <= subGroupIndex && subGroupIndex < subGroups.count()) {
0220         return childCount(subGroups.at(subGroupIndex));
0221     }
0222 
0223     return 0;
0224 }
0225 
0226 QModelIndex CheckListModel::parent(const QModelIndex& child) const
0227 {
0228     if (!child.isValid()) {
0229         return QModelIndex();
0230     }
0231 
0232     auto* childCheckGroup = static_cast<CheckGroup*>(child.internalPointer());
0233     if (!childCheckGroup) {
0234         return QModelIndex();
0235     }
0236     if (childCheckGroup == m_rootCheckGroup.data()) {
0237         return createIndex(0, 0, nullptr);
0238     }
0239     auto* parentCheckGroup = childCheckGroup->superGroup();
0240     const auto& subGroups = parentCheckGroup->subGroups();
0241     const int parentRow = subGroups.indexOf(childCheckGroup);
0242     return createIndex(parentRow, 0, parentCheckGroup);
0243 }
0244 
0245 QModelIndex CheckListModel::index(int row, int column, const QModelIndex& parent) const
0246 {
0247     if ((column < NameColumnId) ||(column > CountColumnId) ||
0248         (row < 0) ||
0249         !m_rootCheckGroup) {
0250         return QModelIndex();
0251     }
0252 
0253     if (!parent.isValid()) {
0254         if (1 <= row) {
0255             return QModelIndex();
0256         }
0257         return createIndex(row, column, nullptr);
0258     }
0259 
0260     auto* superCheckGroup = checkGroup(parent);
0261     if (row >= childCount(superCheckGroup)) {
0262         return QModelIndex();
0263     }
0264 
0265     return createIndex(row, column, superCheckGroup);
0266 }
0267 
0268 Qt::ItemFlags CheckListModel::flags(const QModelIndex& index) const
0269 {
0270     if (!index.isValid()) {
0271         return Qt::NoItemFlags;
0272     }
0273 
0274     if (index.column() == CountColumnId) {
0275         return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
0276     }
0277 
0278     if (!m_isEditable) {
0279         return  Qt::ItemIsEnabled | Qt::ItemIsSelectable;
0280     }
0281 
0282     auto* checkGroup = static_cast<const CheckGroup*>(index.internalPointer());
0283 
0284     // root?
0285     if (!checkGroup) {
0286         return  Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
0287     }
0288 
0289     return  Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsUserTristate;
0290 }
0291 
0292 int CheckListModel::childCount(const CheckGroup* checkGroup) const
0293 {
0294     return checkGroup->subGroups().count() + checkGroup->checkNames().count();
0295 }
0296 
0297 CheckGroup* CheckListModel::checkGroup(const QModelIndex& index) const
0298 {
0299     auto* superCheckGroup = static_cast<CheckGroup*>(index.internalPointer());
0300     if (!superCheckGroup) {
0301         return m_rootCheckGroup.data();
0302     }
0303 
0304     const int subGroupIndex = index.row();
0305     const auto& subGroups = superCheckGroup->subGroups();
0306     Q_ASSERT(0 <= subGroupIndex && subGroupIndex < subGroups.count());
0307     return subGroups.at(subGroupIndex);
0308 }
0309 
0310 
0311 void CheckListModel::setCheckSet(const CheckSet* checkSet)
0312 {
0313     beginResetModel();
0314 
0315     m_checkSet = checkSet;
0316 
0317     m_rootCheckGroup.reset(CheckGroup::fromPlainList(m_checkSet->all()));
0318 
0319     if (m_isDefault) {
0320         m_rootCheckGroup->setEnabledChecks(m_checkSet->defaults());
0321     }
0322 
0323     endResetModel();
0324 }
0325 
0326 
0327 QStringList CheckListModel::enabledChecks() const
0328 {
0329     if (m_isDefault) {
0330         return QStringList();
0331     }
0332 
0333     return m_rootCheckGroup->enabledChecksRules();
0334 }
0335 
0336 void CheckListModel::setEnabledChecks(const QStringList& enabledChecks)
0337 {
0338     beginResetModel();
0339 
0340     if (enabledChecks.isEmpty() && m_checkSet) {
0341         m_rootCheckGroup->setEnabledChecks(m_checkSet->defaults());
0342         m_isDefault = true;
0343     } else {
0344         m_rootCheckGroup->setEnabledChecks(enabledChecks);
0345         m_isDefault = false;
0346     }
0347 
0348     endResetModel();
0349 }
0350 
0351 void CheckListModel::setEditable(bool editable)
0352 {
0353     if (m_isEditable == editable) {
0354         return;
0355     }
0356 
0357     beginResetModel();
0358     m_isEditable = editable;
0359     endResetModel();
0360 }
0361 
0362 void CheckListModel::emitSubGroupDataChanged(const QModelIndex& subGroupIndex)
0363 {
0364     // first group itself
0365     emit dataChanged(subGroupIndex, subGroupIndex, {Qt::CheckStateRole});
0366     const auto countIndex = subGroupIndex.sibling(subGroupIndex.row(), CountColumnId);
0367     emit dataChanged(countIndex, countIndex, {Qt::DisplayRole});
0368 
0369     auto* checkGroup = this->checkGroup(subGroupIndex);
0370     const int subGroupsCount = checkGroup->subGroups().count();
0371 
0372     // subgroups
0373     for (int i = 0; i < subGroupsCount; ++i) {
0374         const auto subSubGroupInxex = index(i, NameColumnId, subGroupIndex);
0375         emitSubGroupDataChanged(subSubGroupInxex);
0376     }
0377 
0378     // checks
0379     const int checksCount = checkGroup->checkNames().count();
0380     if (checksCount > 0) {
0381         const int firstChecksRow = subGroupsCount;
0382         const int lastChecksRow = firstChecksRow + checksCount - 1;
0383         const auto firstCheckIndex = index(firstChecksRow, NameColumnId, subGroupIndex);
0384         const auto lastCheckIndex = index(lastChecksRow, NameColumnId, subGroupIndex);
0385         emit dataChanged(firstCheckIndex, lastCheckIndex, {Qt::CheckStateRole});
0386     }
0387 }
0388 
0389 }
0390 
0391 #include "moc_checklistmodel.cpp"