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

0001 // ct_lvtmdl_errorsmodel.h                                         -*-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_lvtmdl_errorsmodel.h>
0021 
0022 #include <QDebug>
0023 #include <QFontMetrics>
0024 #include <QList>
0025 #include <QString>
0026 
0027 using namespace Codethink::lvtmdl;
0028 
0029 struct DataInfo {
0030     enum Type {
0031         e_ErrorKind,
0032         e_QualifiedName,
0033         e_FileName,
0034         e_ErrorString,
0035     };
0036 
0037     int errorKind;
0038     QString qualifiedName;
0039     QString filename;
0040     QString errorString;
0041 };
0042 
0043 struct ErrorsModel::Private {
0044     QList<DataInfo> messages;
0045 };
0046 
0047 ErrorsModel::ErrorsModel(): d(std::make_unique<ErrorsModel::Private>())
0048 {
0049 }
0050 
0051 ErrorsModel::~ErrorsModel() = default;
0052 
0053 void ErrorsModel::reset()
0054 {
0055     beginResetModel();
0056     d->messages.clear();
0057 
0058     // TODO: Retrieve errors from lvtldr
0059     //    if (d->session) {
0060     //        Transaction transaction(*d->session);
0061     //        const auto errorMessages = d->session->find<lvtcdb::ErrorMessages>();
0062     //        for (auto& errorMessage : errorMessages.resultList()) {
0063     //            d->messages.append(DataInfo{
0064     //                errorMessage->errorKind(),
0065     //                QString::fromStdString(errorMessage->fullyQualifiedName()),
0066     //                QString::fromStdString(errorMessage->fileName()),
0067     //                QString::fromStdString(errorMessage->errorMessage()),
0068     //            });
0069     //        }
0070     //    }
0071 
0072     endResetModel();
0073 }
0074 
0075 int ErrorsModel::rowCount(const QModelIndex& idx) const
0076 {
0077     Q_UNUSED(idx);
0078     return d->messages.count();
0079 }
0080 
0081 int ErrorsModel::columnCount(const QModelIndex& idx) const
0082 {
0083     Q_UNUSED(idx);
0084     return 4;
0085 }
0086 
0087 QVariant ErrorsModel::headerData(int section, Qt::Orientation orientation, int role) const
0088 {
0089     if (orientation == Qt::Orientation::Vertical) {
0090         return {};
0091     }
0092 
0093     if (role != Qt::DisplayRole) {
0094         return {};
0095     }
0096 
0097     switch (section) {
0098     case DataInfo::Type::e_ErrorKind:
0099         return tr("Type");
0100     case DataInfo::Type::e_QualifiedName:
0101         return tr("Qualified Name");
0102     case DataInfo::Type::e_FileName:
0103         return tr("File");
0104     case DataInfo::Type::e_ErrorString:
0105         return tr("Error Message");
0106     }
0107 
0108     return {};
0109 }
0110 
0111 QVariant ErrorsModel::data(const QModelIndex& idx, int role) const
0112 {
0113     if (role != Qt::DisplayRole && role != Qt::ToolTipRole && role != Qt::SizeHintRole) {
0114         return {};
0115     }
0116 
0117     const auto thisValue = d->messages.at(idx.row());
0118     if (role == Qt::DisplayRole) {
0119         switch (idx.column()) {
0120         case DataInfo::Type::e_ErrorKind:
0121             return thisValue.errorKind == 0 ? tr("Compiler Messages") : tr("Parse Messages");
0122 
0123         case DataInfo::Type::e_ErrorString:
0124             return thisValue.errorString;
0125         case DataInfo::Type::e_FileName:
0126             return thisValue.filename;
0127         case DataInfo::Type::e_QualifiedName:
0128             return thisValue.qualifiedName;
0129         }
0130     } else if (role == Qt::ToolTipRole) {
0131         return thisValue.errorString;
0132     }
0133 
0134     return {};
0135 }
0136 
0137 struct ErrorModelFilter::Private {
0138     bool filterCompilerMessages = false;
0139     bool filterParseMessages = false;
0140     bool invertStringFilter = false;
0141     QAbstractItemModel *ignoreCategoriesModel = nullptr;
0142     QString filterString;
0143 };
0144 
0145 ErrorModelFilter::ErrorModelFilter(): d(std::make_unique<ErrorModelFilter::Private>())
0146 {
0147 }
0148 
0149 ErrorModelFilter::~ErrorModelFilter() = default;
0150 
0151 bool ErrorModelFilter::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
0152 {
0153     Q_UNUSED(source_parent);
0154 
0155     auto *currModel = qobject_cast<ErrorsModel *>(sourceModel());
0156 
0157     const QModelIndex idx = currModel->index(source_row, DataInfo::Type::e_ErrorKind);
0158     const QVariant data = currModel->data(idx, Qt::DisplayRole);
0159     const QString type = data.toString();
0160 
0161     if (d->filterCompilerMessages && type == tr("Compiler Messages")) {
0162         return false;
0163     }
0164     if (d->filterParseMessages && type == tr("Parse Messages")) {
0165         return false;
0166     }
0167 
0168     if (d->filterString.size()) {
0169         const QModelIndex messageIdx = currModel->index(source_row, DataInfo::Type::e_ErrorString);
0170         const QString currMessage = currModel->data(messageIdx, Qt::DisplayRole).toString();
0171         const bool lineContainsFilter = currMessage.contains(d->filterString);
0172 
0173         if (d->invertStringFilter) {
0174             return !lineContainsFilter;
0175         }
0176         return lineContainsFilter;
0177     }
0178 
0179     return true;
0180 }
0181 
0182 bool ErrorModelFilter::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const
0183 {
0184     Q_UNUSED(source_left);
0185     Q_UNUSED(source_right);
0186     return true;
0187 }
0188 
0189 void ErrorModelFilter::setFilterCompilerMessages(bool filter)
0190 {
0191     if (d->filterCompilerMessages == filter) {
0192         return;
0193     }
0194     d->filterCompilerMessages = filter;
0195     invalidateFilter();
0196 }
0197 
0198 void ErrorModelFilter::setFilterParseMessages(bool filter)
0199 {
0200     if (d->filterParseMessages == filter) {
0201         return;
0202     }
0203     d->filterParseMessages = filter;
0204     invalidateFilter();
0205 }
0206 
0207 void ErrorModelFilter::setIgnoreCategoriesModel(QAbstractItemModel *model)
0208 {
0209     if (d->ignoreCategoriesModel) {
0210         disconnect(d->ignoreCategoriesModel, &QAbstractItemModel::rowsInserted, this, nullptr);
0211         disconnect(d->ignoreCategoriesModel, &QAbstractItemModel::rowsRemoved, this, nullptr);
0212     }
0213 
0214     d->ignoreCategoriesModel = model;
0215     connect(model, &QAbstractItemModel::rowsInserted, this, [this] {
0216         invalidateFilter();
0217     });
0218 
0219     connect(model, &QAbstractItemModel::rowsRemoved, this, [this] {
0220         invalidateFilter();
0221     });
0222 }
0223 
0224 void ErrorModelFilter::setFilterString(const QString& str)
0225 {
0226     if (d->filterString == str) {
0227         return;
0228     }
0229     d->filterString = str;
0230     invalidateFilter();
0231 }
0232 
0233 void ErrorModelFilter::setInvertMessageFilter(bool value)
0234 {
0235     if (d->invertStringFilter == value) {
0236         return;
0237     }
0238     d->invertStringFilter = value;
0239     invalidateFilter();
0240 }