File indexing completed on 2024-04-28 05:49:05
0001 /* 0002 SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 #include "gitstatusmodel.h" 0007 0008 #include <KColorScheme> 0009 #include <QFileInfo> 0010 #include <QFont> 0011 #include <QIcon> 0012 #include <QMimeDatabase> 0013 0014 #include <KLocalizedString> 0015 0016 static constexpr int Staged = 0; 0017 static constexpr int Changed = 1; 0018 static constexpr int Conflict = 2; 0019 static constexpr int Untrack = 3; 0020 static constexpr quintptr Root = 0xFFFFFFFF; 0021 0022 GitStatusModel::GitStatusModel(QObject *parent) 0023 : QAbstractItemModel(parent) 0024 { 0025 // setup root rows 0026 beginInsertRows(QModelIndex(), 0, 3); 0027 endInsertRows(); 0028 } 0029 0030 QModelIndex GitStatusModel::index(int row, int column, const QModelIndex &parent) const 0031 { 0032 auto rootIndex = Root; 0033 if (parent.isValid()) { 0034 if (parent.internalId() == Root) { 0035 rootIndex = parent.row(); 0036 } 0037 } 0038 return createIndex(row, column, rootIndex); 0039 } 0040 0041 QModelIndex GitStatusModel::parent(const QModelIndex &child) const 0042 { 0043 if (!child.isValid()) { 0044 return QModelIndex(); 0045 } 0046 0047 return createIndex(child.internalId(), 0, Root); 0048 } 0049 0050 int GitStatusModel::rowCount(const QModelIndex &parent) const 0051 { 0052 if (!parent.isValid()) { 0053 return 4; 0054 } 0055 0056 if (parent.internalId() == Root) { 0057 if (parent.row() < 0 || parent.row() > 3) { 0058 return 0; 0059 } 0060 0061 return m_nodes[parent.row()].size(); 0062 } 0063 return 0; 0064 } 0065 0066 int GitStatusModel::columnCount(const QModelIndex &) const 0067 { 0068 return 2; 0069 } 0070 0071 QVariant GitStatusModel::data(const QModelIndex &index, int role) const 0072 { 0073 if (!index.isValid()) { 0074 return {}; 0075 } 0076 0077 const int row = index.row(); 0078 0079 if (index.internalId() == Root) { 0080 if (role == Qt::DisplayRole) { 0081 if (index.column() == 1) { 0082 return QString::number(m_nodes[row].count()); 0083 } else { 0084 if (row == Staged) { 0085 return i18n("Staged"); 0086 } else if (row == Untrack) { 0087 return i18n("Untracked"); 0088 } else if (row == Conflict) { 0089 return i18n("Conflict"); 0090 } else if (row == Changed) { 0091 return i18n("Modified"); 0092 } else { 0093 Q_UNREACHABLE(); 0094 } 0095 } 0096 } else if (role == Qt::FontRole) { 0097 QFont bold; 0098 bold.setBold(true); 0099 return bold; 0100 } else if (role == Role::TreeItemType) { 0101 return NodeStage + row; 0102 } else if (role == Qt::TextAlignmentRole) { 0103 if (index.column() == 0) { 0104 return (int)(Qt::AlignLeft | Qt::AlignVCenter); 0105 } else { 0106 return (int)(Qt::AlignRight | Qt::AlignVCenter); 0107 } 0108 } 0109 } else { 0110 int rootIndex = index.internalId(); 0111 if (rootIndex < 0 || rootIndex > 3) { 0112 return QVariant(); 0113 } 0114 0115 if (role == Qt::DisplayRole) { 0116 if (index.column() == 0) { 0117 auto fileStr = QString::fromUtf8(m_nodes[rootIndex].at(row).file); 0118 QFileInfo fi(fileStr); 0119 const auto filename = fi.fileName(); 0120 if (filename.isEmpty()) { 0121 return m_nodes[rootIndex].at(row).file; 0122 } 0123 if (rootIndex < Untrack && m_nonUniqueFileNames.contains(filename)) { 0124 const auto path = fi.path(); 0125 const auto i = path.lastIndexOf(QLatin1Char('/')); 0126 if (i != -1) { 0127 return path.mid(i + 1).append(QLatin1Char('/')).append(filename); 0128 } 0129 return fileStr; 0130 } 0131 return filename; 0132 } else { 0133 int a = m_nodes[rootIndex].at(row).linesAdded; 0134 int r = m_nodes[rootIndex].at(row).linesRemoved; 0135 auto add = QString::number(a); 0136 auto sub = QString::number(r); 0137 QString statusChar(QLatin1Char(m_nodes[rootIndex].at(row).statusChar)); 0138 QString ret = QStringLiteral("+") + add + QStringLiteral(" -") + sub + QStringLiteral(" ") + statusChar; 0139 return ret; 0140 } 0141 } else if (role == FileNameRole) { 0142 return m_nodes[rootIndex].at(row).file; 0143 } else if (role == Qt::DecorationRole) { 0144 if (index.column() == 0) { 0145 const QString file = QString::fromUtf8(m_nodes[rootIndex].at(row).file); 0146 return QIcon::fromTheme(QMimeDatabase().mimeTypeForFile(file, QMimeDatabase::MatchExtension).iconName()); 0147 } 0148 } else if (role == Role::TreeItemType) { 0149 return ItemType::NodeFile; 0150 } else if (role == Qt::ToolTipRole) { 0151 return QString(QString::fromUtf8(m_nodes[rootIndex].at(row).file) + GitUtils::statusString(m_nodes[rootIndex].at(row).status)); 0152 } else if (role == Qt::TextAlignmentRole) { 0153 if (index.column() == 0) { 0154 return (int)(Qt::AlignLeft | Qt::AlignVCenter); 0155 } else { 0156 return (int)(Qt::AlignRight | Qt::AlignVCenter); 0157 } 0158 } else if (role == Qt::ForegroundRole) { 0159 if (index.column() == 1 && rootIndex > 0) { 0160 return KColorScheme().foreground(KColorScheme::NegativeText).color(); 0161 } else if (index.column() == 1 && rootIndex == 0) { 0162 return KColorScheme().foreground(KColorScheme::PositiveText).color(); 0163 } 0164 } else if (role == Role::GitItemType) { 0165 return (ItemType)rootIndex; 0166 } 0167 } 0168 0169 return {}; 0170 } 0171 0172 QModelIndex GitStatusModel::indexForFilename(const QString &file) 0173 { 0174 const auto ba = file.toUtf8(); 0175 bool checkUntracked = m_nodes[Untrack].size() < 500; 0176 for (int i = 0; i < Untrack + int(checkUntracked); ++i) { 0177 const auto &items = m_nodes[i]; 0178 int r = 0; 0179 for (const auto &item : items) { 0180 if (ba.endsWith(item.file)) { 0181 // match 0182 return index(r, 0, getModelIndex(static_cast<ItemType>(i))); 0183 } 0184 r++; 0185 } 0186 } 0187 return {}; 0188 } 0189 0190 void GitStatusModel::setStatusItems(GitUtils::GitParsedStatus status) 0191 { 0192 beginResetModel(); 0193 m_nodes[Staged] = std::move(status.staged); 0194 m_nodes[Changed] = std::move(status.changed); 0195 m_nodes[Conflict] = std::move(status.unmerge); 0196 m_nodes[Untrack] = std::move(status.untracked); 0197 m_nonUniqueFileNames = std::move(status.nonUniqueFileNames); 0198 endResetModel(); 0199 }