File indexing completed on 2024-04-28 05:48:39
0001 /*************************************************************************** 0002 * This file is part of Kate build plugin * 0003 * SPDX-FileCopyrightText: 2014 Kåre Särs <kare.sars@iki.fi> * 0004 * * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later * 0006 ***************************************************************************/ 0007 0008 #include "TargetModel.h" 0009 #include <KLocalizedString> 0010 #include <QDebug> 0011 #include <QTimer> 0012 0013 namespace 0014 { 0015 struct NodeInfo { 0016 int rootRow = -1; 0017 int targetSetRow = -1; 0018 int commandRow = -1; 0019 0020 bool isCommand() const 0021 { 0022 return rootRow != -1 && targetSetRow != -1 && commandRow != -1; 0023 } 0024 0025 bool isTargetSet() const 0026 { 0027 return rootRow != -1 && targetSetRow != -1 && commandRow == -1; 0028 } 0029 0030 bool isRoot() const 0031 { 0032 return rootRow != -1 && targetSetRow == -1 && commandRow == -1; 0033 } 0034 0035 bool isValid() const 0036 { 0037 return rootRow != -1; 0038 } 0039 }; 0040 } 0041 0042 static QDebug operator<<(QDebug debug, const NodeInfo &node) 0043 { 0044 QDebugStateSaver saver(debug); 0045 debug << "Node:" << node.rootRow << node.targetSetRow << node.commandRow; 0046 return debug; 0047 } 0048 0049 TargetModel::TargetSet::TargetSet(const QString &_name, const QString &_dir) 0050 : name(_name) 0051 , workDir(_dir) 0052 { 0053 } 0054 0055 /** 0056 * This is the logical structure of the nodes in the model. 0057 * 1) In the root we have Session and/or Project 0058 * 2) Under these we have the TargetSets (working directory) 0059 * 3) Under the TargetSets we have the Targets (commands to execute and/or run commands) 0060 * 0061 * --- Session Targets 0062 * - TargetSet 0063 * - Command, Run 0064 * - ... 0065 * - TargetSet 0066 * - Command, Run 0067 * - ... 0068 * 0069 * --- Project Targets 0070 * - TargetSet 0071 * - Command, Run 0072 * - ... 0073 * - TargetSet 0074 * - Command, Run 0075 * - ... 0076 * 0077 * 0078 * How to interpret QModelIndex::internalId: 0079 * if internalId == InvalidIndex -> This is a Root element 0080 * else if internalId & TargetSetRowMask == TargetSetRowMask -> This is a TargetSet Node 0081 * else this is a command node 0082 * (internalId == "parent rows") 0083 * 0084 * column 0 is command name, target-set name or Session/Project 0085 * column 1 is the command or working directory 0086 * column 2 is the run command 0087 */ 0088 0089 // Topmost bit is used for RootRow 0 or 1 0090 static constexpr int RootRowShift = sizeof(quintptr) * 8 - 1; 0091 0092 // One empty bit is reserved between RootRow and TargetSetRow 0093 static constexpr quintptr TargetSetRowMask = ~((quintptr)3 << (RootRowShift - 1)); 0094 0095 /** This function converts the internalId to root-row, which can be either 0 or 1 as we only can have two of them. ' 0096 * @return 0 or 1 if successful or -1 if not a valid internalId 0097 */ 0098 static int idToRootRow(quintptr internalId) 0099 { 0100 if (internalId == TargetModel::InvalidIndex) { 0101 return -1; 0102 } 0103 return internalId >> RootRowShift; 0104 } 0105 0106 static int idToTargetSetRow(quintptr internalId) 0107 { 0108 if (internalId == TargetModel::InvalidIndex) { 0109 return -1; 0110 } 0111 0112 if ((internalId & TargetSetRowMask) == TargetSetRowMask) { 0113 return -1; 0114 } 0115 return internalId &= TargetSetRowMask; 0116 } 0117 0118 static quintptr toInternalId(int rootRow, int targetSetRow) 0119 { 0120 if (rootRow < 0) { 0121 return TargetModel::InvalidIndex; 0122 } 0123 0124 if (targetSetRow < 0) { 0125 return TargetSetRowMask + ((quintptr)rootRow << RootRowShift); 0126 } 0127 0128 return ((quintptr)targetSetRow & TargetSetRowMask) + ((quintptr)rootRow << RootRowShift); 0129 } 0130 0131 static NodeInfo modelToNodeInfo(const QModelIndex &itemIndex) 0132 { 0133 NodeInfo idx; 0134 if (!itemIndex.isValid()) { 0135 return idx; 0136 } 0137 0138 if (itemIndex.internalId() == TargetModel::InvalidIndex) { 0139 // This is a root node 0140 idx.rootRow = itemIndex.row(); 0141 return idx; 0142 } 0143 0144 int rootRow = idToRootRow(itemIndex.internalId()); 0145 int targetSetRow = idToTargetSetRow(itemIndex.internalId()); 0146 if (rootRow != -1 && targetSetRow == -1) { 0147 // This is a TargetSet node 0148 idx.rootRow = rootRow; 0149 idx.targetSetRow = itemIndex.row(); 0150 } // 0151 else if (rootRow != -1 && targetSetRow != -1) { 0152 // This is a Command node 0153 idx.rootRow = rootRow; 0154 idx.targetSetRow = targetSetRow; 0155 idx.commandRow = itemIndex.row(); 0156 } 0157 return idx; 0158 } 0159 0160 static bool nodeExists(const QList<TargetModel::RootNode> &rootNodes, const NodeInfo &node) 0161 { 0162 if (!node.isValid()) { 0163 return false; 0164 } 0165 0166 if (node.rootRow < 0 || node.rootRow >= rootNodes.size()) { 0167 return false; 0168 } 0169 0170 if (node.isRoot()) { 0171 return true; 0172 } 0173 0174 const QList<TargetModel::TargetSet> &targets = rootNodes[node.rootRow].targetSets; 0175 if (node.targetSetRow >= targets.size()) { 0176 return false; 0177 } 0178 0179 if (node.isTargetSet()) { 0180 return true; 0181 } 0182 0183 const QList<TargetModel::Command> &commands = targets[node.targetSetRow].commands; 0184 if (node.commandRow >= commands.size()) { 0185 qWarning() << "Command row out of bounds" << node; 0186 return false; 0187 } 0188 // The node is valid, not root and not a target-set and command-row is valid 0189 return true; 0190 } 0191 0192 TargetModel::TargetModel(QObject *parent) 0193 : QAbstractItemModel(parent) 0194 { 0195 m_rootNodes.append(RootNode()); 0196 m_rootNodes.append(RootNode()); 0197 // By default the project branch is second 0198 m_rootNodes[1].isProject = true; 0199 } 0200 TargetModel::~TargetModel() 0201 { 0202 } 0203 0204 void TargetModel::clear(bool setSessionFirst) 0205 { 0206 beginResetModel(); 0207 m_rootNodes.clear(); 0208 m_rootNodes.append(RootNode()); 0209 m_rootNodes.append(RootNode()); 0210 m_rootNodes[setSessionFirst ? 1 : 0].isProject = true; 0211 endResetModel(); 0212 } 0213 0214 QModelIndex TargetModel::sessionRootIndex() const 0215 { 0216 for (int i = 0; i < m_rootNodes.size(); ++i) { 0217 if (!m_rootNodes[i].isProject) { 0218 return index(i, 0); 0219 } 0220 } 0221 return QModelIndex(); 0222 } 0223 0224 QModelIndex TargetModel::projectRootIndex() const 0225 { 0226 for (int i = 0; i < m_rootNodes.size(); ++i) { 0227 if (m_rootNodes[i].isProject) { 0228 return index(i, 0); 0229 } 0230 } 0231 return QModelIndex(); 0232 } 0233 0234 QModelIndex TargetModel::insertTargetSetAfter(const QModelIndex &beforeIndex, const QString &setName, const QString &workDir) 0235 { 0236 // qDebug() << "Inserting TargetSet after:" << beforeIndex << setName <<workDir; 0237 NodeInfo bNode = modelToNodeInfo(beforeIndex); 0238 if (!nodeExists(m_rootNodes, bNode)) { 0239 // Add the new target-set to the end of the first root node (creating the root if needed) 0240 if (m_rootNodes.isEmpty()) { 0241 beginInsertRows(QModelIndex(), 0, 0); 0242 m_rootNodes.append(RootNode()); 0243 endInsertRows(); 0244 } 0245 bNode.rootRow = 0; 0246 bNode.targetSetRow = m_rootNodes[0].targetSets.size() - 1; 0247 } 0248 0249 if (bNode.isRoot()) { 0250 bNode.targetSetRow = m_rootNodes[bNode.rootRow].targetSets.size() - 1; 0251 } 0252 0253 QList<TargetSet> &targetSets = m_rootNodes[bNode.rootRow].targetSets; 0254 0255 // Make the name unique 0256 QString newName = setName; 0257 for (int i = 0; i < targetSets.count(); i++) { 0258 if (targetSets[i].name == newName) { 0259 newName += QStringLiteral("+"); 0260 i = -1; 0261 } 0262 } 0263 bNode.targetSetRow++; 0264 0265 beginInsertRows(index(bNode.rootRow, 0), bNode.targetSetRow, bNode.targetSetRow); 0266 TargetModel::TargetSet targetSet(newName, workDir); 0267 targetSets.insert(bNode.targetSetRow, targetSet); 0268 endInsertRows(); 0269 return index(bNode.targetSetRow, 0, index(bNode.rootRow, 0)); 0270 } 0271 0272 QModelIndex TargetModel::addCommandAfter(const QModelIndex &beforeIndex, const QString &cmdName, const QString &buildCmd, const QString &runCmd) 0273 { 0274 // qDebug() << "addCommandAfter" << beforeIndex << cmdName; 0275 NodeInfo bNode = modelToNodeInfo(beforeIndex); 0276 if (!nodeExists(m_rootNodes, bNode)) { 0277 // Add the new command to the end of the first target-set of the first root node (creating the root and target-set if needed) 0278 if (m_rootNodes.isEmpty()) { 0279 beginInsertRows(QModelIndex(), 0, 0); 0280 m_rootNodes.append(RootNode()); 0281 endInsertRows(); 0282 } 0283 if (m_rootNodes[0].targetSets.isEmpty()) { 0284 beginInsertRows(index(0, 0), 0, 0); 0285 m_rootNodes[0].targetSets.append(TargetSet(i18n("Target Set"), QString())); 0286 endInsertRows(); 0287 } 0288 bNode.rootRow = 0; 0289 bNode.targetSetRow = 0; 0290 bNode.commandRow = m_rootNodes[0].targetSets[0].commands.size() - 1; 0291 } 0292 0293 if (bNode.isRoot()) { 0294 // Add the new command to the first target-set of this root node (creating the targetset if needed) 0295 if (m_rootNodes[bNode.rootRow].targetSets.isEmpty()) { 0296 beginInsertRows(index(bNode.rootRow, 0), 0, 0); 0297 m_rootNodes[bNode.rootRow].targetSets.append(TargetSet(i18n("Target Set"), QString())); 0298 endInsertRows(); 0299 } 0300 bNode.targetSetRow = 0; 0301 bNode.commandRow = m_rootNodes[bNode.rootRow].targetSets[0].commands.size() - 1; 0302 } 0303 0304 if (bNode.isTargetSet()) { 0305 bNode.commandRow = m_rootNodes[bNode.rootRow].targetSets[bNode.targetSetRow].commands.size() - 1; 0306 } 0307 0308 // Now we have the place to insert the new command 0309 QList<Command> &commands = m_rootNodes[bNode.rootRow].targetSets[bNode.targetSetRow].commands; 0310 // make the name unique 0311 QString newName = cmdName; 0312 for (int i = 0; i < commands.count(); ++i) { 0313 if (commands[i].name == newName) { 0314 newName += QStringLiteral("+"); 0315 i = -1; 0316 } 0317 } 0318 0319 // it is the row after beforeIndex, where we want to insert the command 0320 bNode.commandRow++; 0321 0322 QModelIndex targetSetIndex = index(bNode.targetSetRow, 0, index(bNode.rootRow, 0)); 0323 beginInsertRows(targetSetIndex, bNode.commandRow, bNode.commandRow); 0324 commands.insert(bNode.commandRow, {newName, buildCmd, runCmd}); 0325 endInsertRows(); 0326 return index(bNode.commandRow, 0, targetSetIndex); 0327 } 0328 0329 QModelIndex TargetModel::copyTargetOrSet(const QModelIndex ©Index) 0330 { 0331 NodeInfo cpNode = modelToNodeInfo(copyIndex); 0332 if (!nodeExists(m_rootNodes, cpNode)) { 0333 return QModelIndex(); 0334 } 0335 0336 if (cpNode.isRoot()) { 0337 return QModelIndex(); 0338 } 0339 0340 QList<TargetSet> &targetSets = m_rootNodes[cpNode.rootRow].targetSets; 0341 QModelIndex rootIndex = index(cpNode.rootRow, 0); 0342 if (cpNode.isTargetSet()) { 0343 TargetSet targetSetCopy = targetSets[cpNode.targetSetRow]; 0344 // Make the name unique 0345 QString newName = targetSetCopy.name; 0346 for (int i = 0; i < targetSets.size(); ++i) { 0347 if (targetSets[i].name == newName) { 0348 newName += QStringLiteral("+"); 0349 i = -1; 0350 } 0351 } 0352 targetSetCopy.name = newName; 0353 beginInsertRows(rootIndex, cpNode.targetSetRow + 1, cpNode.targetSetRow + 1); 0354 targetSets.insert(cpNode.targetSetRow + 1, targetSetCopy); 0355 endInsertRows(); 0356 return index(cpNode.targetSetRow + 1, 0, rootIndex); 0357 } 0358 0359 // This is a command-row 0360 QList<Command> &commands = targetSets[cpNode.targetSetRow].commands; 0361 Command commandCopy = commands[cpNode.commandRow]; 0362 QString newName = commandCopy.name; 0363 for (int i = 0; i < commands.size(); i++) { 0364 if (commands[i].name == newName) { 0365 newName += QStringLiteral("+"); 0366 i = -1; 0367 } 0368 } 0369 commandCopy.name = newName; 0370 QModelIndex tgSetIndex = index(cpNode.targetSetRow, 0, rootIndex); 0371 beginInsertRows(tgSetIndex, cpNode.commandRow + 1, cpNode.commandRow + 1); 0372 commands.insert(cpNode.commandRow + 1, commandCopy); 0373 endInsertRows(); 0374 return index(cpNode.commandRow + 1, 0, tgSetIndex); 0375 } 0376 0377 void TargetModel::deleteItem(const QModelIndex &itemIndex) 0378 { 0379 if (!itemIndex.isValid()) { 0380 return; 0381 } 0382 0383 NodeInfo node = modelToNodeInfo(itemIndex); 0384 if (!nodeExists(m_rootNodes, node)) { 0385 qDebug() << "Node does not exist:" << node; 0386 return; 0387 } 0388 0389 if (node.isRoot()) { 0390 beginRemoveRows(itemIndex, 0, m_rootNodes[node.rootRow].targetSets.size() - 1); 0391 m_rootNodes[node.rootRow].targetSets.clear(); 0392 endRemoveRows(); 0393 } else if (node.isTargetSet()) { 0394 beginRemoveRows(itemIndex.parent(), itemIndex.row(), itemIndex.row()); 0395 m_rootNodes[node.rootRow].targetSets.removeAt(node.targetSetRow); 0396 endRemoveRows(); 0397 } else { 0398 beginRemoveRows(itemIndex.parent(), itemIndex.row(), itemIndex.row()); 0399 m_rootNodes[node.rootRow].targetSets[node.targetSetRow].commands.removeAt(node.commandRow); 0400 endRemoveRows(); 0401 } 0402 } 0403 0404 void TargetModel::deleteProjectTargerts() 0405 { 0406 for (int i = 0; i < m_rootNodes.count(); ++i) { 0407 if (m_rootNodes[i].isProject && m_rootNodes[i].targetSets.count() > 0) { 0408 beginRemoveRows(index(i, 0), 0, m_rootNodes[i].targetSets.count() - 1); 0409 m_rootNodes[i].targetSets.clear(); 0410 endRemoveRows(); 0411 return; 0412 } 0413 } 0414 } 0415 0416 void TargetModel::moveRowUp(const QModelIndex &itemIndex) 0417 { 0418 if (!itemIndex.isValid()) { 0419 return; 0420 } 0421 NodeInfo node = modelToNodeInfo(itemIndex); 0422 if (!nodeExists(m_rootNodes, node)) { 0423 qDebug() << "Node does not exist:" << node; 0424 return; 0425 } 0426 int row = itemIndex.row(); 0427 if (row == 0) { 0428 return; // This is valid for all the three cases 0429 } 0430 0431 QModelIndex parent = itemIndex.parent(); // This parent is valid for all the cases 0432 0433 if (node.isRoot()) { 0434 beginMoveRows(parent, row, row, parent, row - 1); 0435 m_rootNodes.move(row, row - 1); 0436 endMoveRows(); 0437 return; 0438 } 0439 0440 QList<TargetSet> &targetSets = m_rootNodes[node.rootRow].targetSets; 0441 if (node.isTargetSet()) { 0442 beginMoveRows(parent, row, row, parent, row - 1); 0443 targetSets.move(row, row - 1); 0444 endMoveRows(); 0445 return; 0446 } 0447 0448 // It is a command-row 0449 QList<Command> &commands = targetSets[node.targetSetRow].commands; 0450 beginMoveRows(parent, row, row, parent, row - 1); 0451 commands.move(row, row - 1); 0452 endMoveRows(); 0453 } 0454 0455 void TargetModel::moveRowDown(const QModelIndex &itemIndex) 0456 { 0457 if (!itemIndex.isValid()) { 0458 return; 0459 } 0460 NodeInfo node = modelToNodeInfo(itemIndex); 0461 if (!nodeExists(m_rootNodes, node)) { 0462 qDebug() << "Node does not exist:" << node; 0463 return; 0464 } 0465 0466 // These are valid for all the row types 0467 int row = itemIndex.row(); 0468 QModelIndex parent = itemIndex.parent(); 0469 0470 if (node.isRoot()) { 0471 if (row >= m_rootNodes.size() - 1) { 0472 return; 0473 } 0474 beginMoveRows(parent, row, row, parent, row + 2); 0475 m_rootNodes.move(row, row + 1); 0476 endMoveRows(); 0477 return; 0478 } 0479 0480 QList<TargetSet> &targetSets = m_rootNodes[node.rootRow].targetSets; 0481 if (node.isTargetSet()) { 0482 beginMoveRows(parent, row, row, parent, row + 2); 0483 targetSets.move(row, row + 1); 0484 endMoveRows(); 0485 return; 0486 } 0487 0488 // It is a command-row 0489 QList<Command> &commands = targetSets[node.targetSetRow].commands; 0490 beginMoveRows(parent, row, row, parent, row + 2); 0491 commands.move(row, row + 1); 0492 endMoveRows(); 0493 } 0494 0495 const QList<TargetModel::TargetSet> TargetModel::sessionTargetSets() const 0496 { 0497 for (int i = 0; i < m_rootNodes.size(); ++i) { 0498 if (m_rootNodes[i].isProject == false) { 0499 return m_rootNodes[i].targetSets; 0500 } 0501 } 0502 return QList<TargetModel::TargetSet>(); 0503 } 0504 0505 const QList<TargetModel::TargetSet> TargetModel::projectTargetSets() const 0506 { 0507 for (int i = 0; i < m_rootNodes.size(); ++i) { 0508 if (m_rootNodes[i].isProject == true) { 0509 return m_rootNodes[i].targetSets; 0510 } 0511 } 0512 return QList<TargetModel::TargetSet>(); 0513 } 0514 0515 QVariant TargetModel::data(const QModelIndex &index, int role) const 0516 { 0517 if (!index.isValid()) { 0518 qWarning() << "Invalid index" << index; 0519 return QVariant(); 0520 } 0521 0522 NodeInfo node = modelToNodeInfo(index); 0523 if (!nodeExists(m_rootNodes, node)) { 0524 qDebug() << "Node does not exist:" << node; 0525 return QVariant(); 0526 } 0527 0528 if (node.isRoot()) { 0529 if ((role == Qt::DisplayRole || role == Qt::ToolTipRole) && index.column() == 0) { 0530 return m_rootNodes[node.rootRow].isProject ? i18n("Project") : i18n("Session"); 0531 } else if (role == RowTypeRole) { 0532 return RowType::RootRow; 0533 } else if (role == IsProjectTargetRole) { 0534 return m_rootNodes[node.rootRow].isProject; 0535 } 0536 return QVariant(); 0537 } 0538 0539 // This is either a TargetSet or a Command 0540 const TargetSet &targetSet = m_rootNodes[node.rootRow].targetSets[node.targetSetRow]; 0541 0542 if (node.isTargetSet()) { 0543 // This is a TargetSet node 0544 switch (role) { 0545 case Qt::DisplayRole: 0546 case Qt::EditRole: 0547 case Qt::ToolTipRole: 0548 switch (index.column()) { 0549 case 0: 0550 return targetSet.name; 0551 case 1: 0552 return targetSet.workDir; 0553 } 0554 break; 0555 case CommandRole: 0556 if (targetSet.commands.isEmpty()) { 0557 return QVariant(); 0558 } 0559 return targetSet.commands[0].buildCmd; 0560 case CommandNameRole: 0561 if (targetSet.commands.isEmpty()) { 0562 return QVariant(); 0563 } 0564 return targetSet.commands[0].name; 0565 case WorkDirRole: 0566 return targetSet.workDir.isEmpty() ? QString() : targetSet.workDir.split(QLatin1Char(';')).first(); 0567 case SearchPathsRole: 0568 return targetSet.workDir.split(QLatin1Char(';')); 0569 case TargetSetNameRole: 0570 return targetSet.name; 0571 case RowTypeRole: 0572 return TargetSetRow; 0573 case IsProjectTargetRole: 0574 return m_rootNodes[node.rootRow].isProject; 0575 } 0576 } 0577 0578 if (node.isCommand()) { 0579 const Command &command = targetSet.commands[node.commandRow]; 0580 switch (role) { 0581 case Qt::DisplayRole: 0582 case Qt::EditRole: 0583 case Qt::ToolTipRole: 0584 switch (index.column()) { 0585 case 0: 0586 return command.name; 0587 case 1: 0588 return command.buildCmd; 0589 case 2: 0590 return command.runCmd; 0591 } 0592 break; 0593 case CommandRole: 0594 return command.buildCmd; 0595 case CommandNameRole: 0596 return command.name; 0597 case WorkDirRole: 0598 return targetSet.workDir.isEmpty() ? QString() : targetSet.workDir.split(QLatin1Char(';')).first(); 0599 case SearchPathsRole: 0600 return targetSet.workDir.split(QLatin1Char(';')); 0601 case TargetSetNameRole: 0602 return targetSet.name; 0603 case RowTypeRole: 0604 return CommandRow; 0605 case IsProjectTargetRole: 0606 return m_rootNodes[node.rootRow].isProject; 0607 } 0608 } 0609 0610 return QVariant(); 0611 } 0612 0613 QVariant TargetModel::headerData(int section, Qt::Orientation orientation, int role) const 0614 { 0615 if (role != Qt::DisplayRole) { 0616 return QVariant(); 0617 } 0618 0619 if (orientation != Qt::Horizontal) { 0620 return QVariant(); 0621 } 0622 0623 if (section == 0) { 0624 return i18n("Command/Target-set Name"); 0625 } 0626 if (section == 1) { 0627 return i18n("Working Directory / Command"); 0628 } 0629 if (section == 2) { 0630 return i18n("Run Command"); 0631 } 0632 return QVariant(); 0633 } 0634 0635 bool TargetModel::setData(const QModelIndex &itemIndex, const QVariant &value, int role) 0636 { 0637 if (role != Qt::EditRole) { 0638 return false; 0639 } 0640 if (!itemIndex.isValid()) { 0641 qWarning() << "Invalid index"; 0642 return false; 0643 } 0644 0645 NodeInfo node = modelToNodeInfo(itemIndex); 0646 if (!nodeExists(m_rootNodes, node)) { 0647 qDebug() << "Node does not exist:" << node; 0648 return false; 0649 } 0650 0651 if (node.isRoot()) { 0652 return false; 0653 } 0654 0655 // This is either a TargetSet or a Command 0656 TargetSet &targetSet = m_rootNodes[node.rootRow].targetSets[node.targetSetRow]; 0657 0658 bool editDone = false; 0659 if (node.isTargetSet()) { 0660 switch (itemIndex.column()) { 0661 case 0: 0662 targetSet.name = value.toString(); 0663 editDone = true; 0664 break; 0665 case 1: 0666 targetSet.workDir = value.toString(); 0667 editDone = true; 0668 break; 0669 } 0670 } else { 0671 switch (itemIndex.column()) { 0672 case 0: 0673 targetSet.commands[node.commandRow].name = value.toString(); 0674 editDone = true; 0675 break; 0676 case 1: 0677 targetSet.commands[node.commandRow].buildCmd = value.toString(); 0678 editDone = true; 0679 break; 0680 case 2: 0681 targetSet.commands[node.commandRow].runCmd = value.toString(); 0682 editDone = true; 0683 break; 0684 } 0685 } 0686 if (editDone) { 0687 Q_EMIT dataChanged(itemIndex, itemIndex); 0688 if (m_rootNodes[node.rootRow].isProject) { 0689 Q_EMIT projectTargetChanged(); 0690 } 0691 return true; 0692 } 0693 return false; 0694 } 0695 0696 Qt::ItemFlags TargetModel::flags(const QModelIndex &itemIndex) const 0697 { 0698 if (!itemIndex.isValid()) { 0699 return Qt::NoItemFlags; 0700 } 0701 0702 NodeInfo node = modelToNodeInfo(itemIndex); 0703 if (!nodeExists(m_rootNodes, node)) { 0704 return Qt::NoItemFlags; 0705 } 0706 if (node.isRoot()) { 0707 return Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0708 } 0709 0710 // run command column for target set row 0711 if (itemIndex.column() == 2 && node.isTargetSet()) { 0712 return Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0713 } 0714 0715 return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0716 } 0717 0718 int TargetModel::rowCount(const QModelIndex &parent) const 0719 { 0720 if (!parent.isValid()) { 0721 // Invalid index -> root 0722 return m_rootNodes.size(); 0723 } 0724 0725 NodeInfo node = modelToNodeInfo(parent); 0726 if (!nodeExists(m_rootNodes, node)) { 0727 // uncomment for debugging 0728 // qDebug() << "Node does not exist:" << node << parent; 0729 return 0; 0730 } 0731 0732 if (parent.column() != 0) { 0733 // Only first column has children 0734 return 0; 0735 } 0736 0737 if (node.isRoot()) { 0738 return m_rootNodes[node.rootRow].targetSets.size(); 0739 } 0740 0741 if (node.isTargetSet()) { 0742 return m_rootNodes[node.rootRow].targetSets[node.targetSetRow].commands.size(); 0743 } 0744 0745 // This is a command node -> no children 0746 return 0; 0747 } 0748 0749 int TargetModel::columnCount(const QModelIndex &) const 0750 { 0751 return 3; 0752 } 0753 0754 QModelIndex TargetModel::index(int row, int column, const QModelIndex &parent) const 0755 { 0756 if (row < 0) { 0757 return QModelIndex(); 0758 } 0759 0760 if (!parent.isValid()) { 0761 // RootRow Item (Session/Project) 0762 if (row >= m_rootNodes.size()) { 0763 return QModelIndex(); 0764 } 0765 return createIndex(row, column, InvalidIndex); 0766 } 0767 0768 if (parent.column() != 0) { 0769 // Only column 0 can have children. 0770 return QModelIndex(); 0771 } 0772 0773 if (parent.internalId() == InvalidIndex) { 0774 // TargetSet node 0775 int rootRow = parent.row(); 0776 if (rootRow >= m_rootNodes.size() || row >= m_rootNodes.at(rootRow).targetSets.size()) { 0777 return QModelIndex(); 0778 } 0779 return createIndex(row, column, toInternalId(rootRow, -1)); 0780 } 0781 0782 // This is a command node 0783 int rootRow = idToRootRow(parent.internalId()); 0784 int targetSetRow = parent.row(); 0785 if (rootRow >= m_rootNodes.size() || targetSetRow >= m_rootNodes.at(rootRow).targetSets.size()) { 0786 return QModelIndex(); 0787 } 0788 const TargetSet &tgSet = m_rootNodes.at(rootRow).targetSets.at(targetSetRow); 0789 if (row >= tgSet.commands.size()) { 0790 return QModelIndex(); 0791 } 0792 return createIndex(row, column, toInternalId(rootRow, targetSetRow)); 0793 } 0794 0795 QModelIndex TargetModel::parent(const QModelIndex &child) const 0796 { 0797 if (!child.isValid()) { 0798 return QModelIndex(); 0799 } 0800 0801 if (child.internalId() == InvalidIndex) { 0802 // child is a RootRow node -> invalid parent 0803 return QModelIndex(); 0804 } 0805 0806 int rootRow = idToRootRow(child.internalId()); 0807 int targetSetRow = idToTargetSetRow(child.internalId()); 0808 0809 if (targetSetRow == -1) { 0810 // child is a TargetSetNode 0811 return createIndex(rootRow, 0, InvalidIndex); 0812 } 0813 0814 // child is a command node 0815 return createIndex(targetSetRow, 0, toInternalId(rootRow, -1)); 0816 } 0817 0818 #include "moc_TargetModel.cpp"