File indexing completed on 2024-04-28 09:40:59
0001 /*************************************************************************** 0002 * Copyright (C) 2008-2009 by Pino Toscano <pino@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU General Public License as published by * 0006 * the Free Software Foundation; either version 2 of the License, or * 0007 * (at your option) any later version. * 0008 ***************************************************************************/ 0009 0010 #include "alternativemodels.h" 0011 #include "altparser.h" 0012 0013 #include <QComboBox> 0014 #include <QFile> 0015 #include <QFont> 0016 #include <QList> 0017 0018 #include <kiconloader.h> 0019 #include <klocalizedstring.h> 0020 #include <kprocess.h> 0021 0022 #include <algorithm> 0023 0024 #include <config-kalternatives.h> 0025 #include <kalternatives_debug.h> 0026 0027 enum ItemChangeType 0028 { 0029 SelectionItemChange = 1, 0030 AltNumItemChange = 2, 0031 ModeItemChange = 4 0032 }; 0033 Q_DECLARE_FLAGS(ItemChanges, ItemChangeType) 0034 Q_DECLARE_OPERATORS_FOR_FLAGS(ItemChanges) 0035 0036 namespace 0037 { 0038 0039 struct AltNode 0040 { 0041 enum { Type = 0 }; 0042 0043 AltNode(AltNode *pp, int t) 0044 : parent(pp), type(t) {} 0045 virtual ~AltNode() 0046 {} 0047 0048 virtual QList<AltNode*> children() const 0049 { return QList<AltNode*>(); } 0050 virtual int childCount() const 0051 { return 0; } 0052 0053 AltNode *parent; 0054 int type : 3; 0055 }; 0056 0057 struct AltAlternativeNode; 0058 struct AltItemNode; 0059 0060 struct AltRootNode : public AltNode 0061 { 0062 enum { Type = 1 }; 0063 0064 AltRootNode() 0065 : AltNode(Q_NULLPTR, Type) {} 0066 ~AltRootNode() Q_DECL_OVERRIDE 0067 { qDeleteAll(m_children); } 0068 0069 QList<AltNode*> children() const Q_DECL_OVERRIDE 0070 { 0071 QList<AltNode*> c; 0072 std::copy(m_children.begin(), m_children.end(), std::back_inserter(c)); 0073 return c; 0074 } 0075 int childCount() const Q_DECL_OVERRIDE 0076 { return m_children.count(); } 0077 0078 QList<AltItemNode*> m_children; 0079 }; 0080 0081 struct AltItemNode : public AltNode 0082 { 0083 enum { Type = 2 }; 0084 0085 AltItemNode(Item *i, AltRootNode *p) 0086 : AltNode(p, Type), item(i) 0087 , changed(false), nbrAltChanged(false), modeChanged(false) 0088 {} 0089 ~AltItemNode() Q_DECL_OVERRIDE 0090 { qDeleteAll(m_children); } 0091 0092 QList<AltNode*> children() const Q_DECL_OVERRIDE 0093 { 0094 QList<AltNode*> c; 0095 std::copy(m_children.begin(), m_children.end(), std::back_inserter(c)); 0096 return c; 0097 } 0098 int childCount() const Q_DECL_OVERRIDE 0099 { return m_children.count(); } 0100 0101 Item *item; 0102 QList<AltAlternativeNode*> m_children; 0103 bool changed : 1; 0104 bool nbrAltChanged : 1; 0105 bool modeChanged : 1; 0106 }; 0107 0108 struct AltAlternativeNode : public AltNode 0109 { 0110 enum { Type = 3 }; 0111 0112 AltAlternativeNode(Alternative *a, AltItemNode *p) 0113 : AltNode(p, Type), alternative(a), selected(false) 0114 {} 0115 0116 Alternative *alternative; 0117 bool selected : 1; 0118 }; 0119 0120 template <class T> 0121 T* altnode_cast(AltNode *n) 0122 { 0123 return n->type > 0 && n->type == T::Type ? static_cast<T*>(n) : Q_NULLPTR; 0124 } 0125 0126 template <> 0127 AltNode* altnode_cast(AltNode *n) 0128 { 0129 return n; 0130 } 0131 0132 } 0133 0134 class AlternativesBaseModelPrivate 0135 { 0136 public: 0137 AlternativesBaseModelPrivate(); 0138 virtual ~AlternativesBaseModelPrivate(); 0139 0140 Q_DECLARE_PUBLIC(AlternativesBaseModel) 0141 0142 virtual void load() = 0; 0143 virtual AltNode* root() const = 0; 0144 QModelIndex indexForItem(AltNode *n, int col) const; 0145 0146 AlternativesBaseModel *q_ptr; 0147 }; 0148 0149 AlternativesBaseModelPrivate::AlternativesBaseModelPrivate() 0150 : q_ptr(Q_NULLPTR) 0151 { 0152 } 0153 0154 AlternativesBaseModelPrivate::~AlternativesBaseModelPrivate() 0155 { 0156 } 0157 0158 QModelIndex AlternativesBaseModelPrivate::indexForItem(AltNode *n, int col) const 0159 { 0160 if (n->parent) 0161 { 0162 const QList<AltNode*> children = n->parent->children(); 0163 const int id = children.indexOf(n); 0164 if (id >= 0 && id < children.count()) 0165 return q_ptr->createIndex(id, col, n); 0166 } 0167 return QModelIndex(); 0168 } 0169 0170 0171 AlternativesBaseModel::AlternativesBaseModel(AlternativesBaseModelPrivate &dd, QObject *parent) 0172 : QAbstractItemModel(parent), d_ptr(&dd) 0173 { 0174 d_ptr->q_ptr = this; 0175 d_ptr->load(); 0176 } 0177 0178 AlternativesBaseModel::~AlternativesBaseModel() 0179 { 0180 delete d_ptr; 0181 } 0182 0183 bool AlternativesBaseModel::hasChildren(const QModelIndex &parent) const 0184 { 0185 if (!parent.isValid()) 0186 return true; 0187 0188 AltNode *n = static_cast<AltNode *>(parent.internalPointer()); 0189 return n->childCount() > 0; 0190 } 0191 0192 QModelIndex AlternativesBaseModel::index(int row, int column, const QModelIndex &parent) const 0193 { 0194 if (row < 0 || column < 0 || column >= columnCount(parent)) 0195 return QModelIndex(); 0196 0197 AltNode *n = parent.isValid() ? static_cast<AltNode *>(parent.internalPointer()) : d_ptr->root(); 0198 const QList<AltNode*> children = n->children(); 0199 if (row < children.count()) 0200 return createIndex(row, column, children.at(row)); 0201 0202 return QModelIndex(); 0203 } 0204 0205 QModelIndex AlternativesBaseModel::parent(const QModelIndex &index) const 0206 { 0207 if (!index.isValid()) 0208 return QModelIndex(); 0209 0210 AltNode *n = static_cast<AltNode *>(index.internalPointer()); 0211 return d_ptr->indexForItem(n->parent, index.column()); 0212 0213 } 0214 0215 int AlternativesBaseModel::rowCount(const QModelIndex &parent) const 0216 { 0217 AltNode *n = parent.isValid() ? static_cast<AltNode *>(parent.internalPointer()) : d_ptr->root(); 0218 return n->childCount(); 0219 } 0220 0221 0222 class AlternativeItemsModelPrivate : public AlternativesBaseModelPrivate 0223 { 0224 public: 0225 AlternativeItemsModelPrivate(const QString &appName); 0226 ~AlternativeItemsModelPrivate(); 0227 0228 void load() Q_DECL_OVERRIDE; 0229 AltNode* root() const Q_DECL_OVERRIDE { return const_cast<AltRootNode *>(&m_root); } 0230 0231 Q_DECLARE_PUBLIC(AlternativeItemsModel) 0232 0233 void itemChanged(AltItemNode *node, ItemChanges changes); 0234 void loadItemNode(AltItemNode *node); 0235 0236 bool isChanged(AltItemNode *node) const; 0237 AltAlternativeNode* findSelectedAlternative(AltItemNode *node, int *index) const; 0238 0239 AltFilesManager *altManager; 0240 AltRootNode m_root; 0241 QString m_appName; 0242 KIconLoader *iconLoader; 0243 QIcon brokenAltIcon; 0244 }; 0245 0246 AlternativeItemsModelPrivate::AlternativeItemsModelPrivate(const QString &appName) 0247 : AlternativesBaseModelPrivate(), altManager(Q_NULLPTR) 0248 , m_appName(appName), iconLoader(new KIconLoader(m_appName)) 0249 , brokenAltIcon(KDE::icon("alternative-broken", iconLoader)) 0250 { 0251 #if defined(DISTRO_DPKG) 0252 altManager = new AltFilesManager("/var/lib/dpkg/alternatives"); 0253 #elif defined(DISTRO_RPM_2) 0254 altManager = new AltFilesManager("/var/lib/alternatives"); 0255 #elif defined(DISTRO_RPM) 0256 altManager = new AltFilesManager("/var/lib/rpm/alternatives"); 0257 #else 0258 qCritical(KALT_LOG) << "Unsupported distribution for KAlternatives."; 0259 #endif 0260 if (altManager && !altManager->parsingOk()) 0261 { 0262 qCDebug(KALT_LOG) << altManager->getErrorMsg(); 0263 delete altManager; 0264 altManager = Q_NULLPTR; 0265 } 0266 } 0267 0268 AlternativeItemsModelPrivate::~AlternativeItemsModelPrivate() 0269 { 0270 delete altManager; 0271 } 0272 0273 void AlternativeItemsModelPrivate::load() 0274 { 0275 if (!altManager) 0276 return; 0277 0278 ItemPtrList *itemslist = altManager->getGlobalAlternativeList(); 0279 Q_FOREACH (Item *i, *itemslist) 0280 { 0281 AltItemNode *newItem = new AltItemNode(i, &m_root); 0282 m_root.m_children.append(newItem); 0283 } 0284 } 0285 0286 void AlternativeItemsModelPrivate::itemChanged(AltItemNode *node, ItemChanges changes) 0287 { 0288 Q_Q(AlternativeItemsModel); 0289 if (changes & SelectionItemChange) 0290 { 0291 node->changed = true; 0292 } 0293 if (changes & AltNumItemChange) 0294 { 0295 node->nbrAltChanged = true; 0296 } 0297 if (changes & ModeItemChange) 0298 { 0299 node->modeChanged = true; 0300 } 0301 const QModelIndex index = indexForItem(node, 0); 0302 emit q->dataChanged(index, index); 0303 } 0304 0305 void AlternativeItemsModelPrivate::loadItemNode(AltItemNode *node) 0306 { 0307 if (!node->m_children.isEmpty()) 0308 return; 0309 0310 AltsPtrList *alts = node->item->getAlternatives(); 0311 Q_FOREACH (Alternative* a, *alts) 0312 { 0313 AltAlternativeNode *altnode = new AltAlternativeNode(a, node); 0314 node->m_children.append(altnode); 0315 altnode->selected = a->isSelected(); 0316 } 0317 } 0318 0319 bool AlternativeItemsModelPrivate::isChanged(AltItemNode *node) const 0320 { 0321 return node->changed || node->nbrAltChanged || node->modeChanged; 0322 } 0323 0324 AltAlternativeNode* AlternativeItemsModelPrivate::findSelectedAlternative(AltItemNode *node, int *index) const 0325 { 0326 const int num = node->m_children.count(); 0327 for (int i = 0; i < num; ++i) 0328 { 0329 AltAlternativeNode *altnode = node->m_children.at(i); 0330 if (altnode->selected) 0331 { 0332 *index = i; 0333 return altnode; 0334 } 0335 } 0336 *index = -1; 0337 return Q_NULLPTR; 0338 } 0339 0340 0341 AlternativeItemsModel::AlternativeItemsModel(const QString &appName, QObject *parent) 0342 : AlternativesBaseModel(*new AlternativeItemsModelPrivate(appName), parent) 0343 { 0344 Q_D(AlternativeItemsModel); 0345 d->iconLoader->setParent(this); 0346 } 0347 0348 AlternativeItemsModel::~AlternativeItemsModel() 0349 { 0350 } 0351 0352 int AlternativeItemsModel::columnCount(const QModelIndex &parent) const 0353 { 0354 Q_UNUSED(parent) 0355 return 1; 0356 } 0357 0358 QVariant AlternativeItemsModel::data(const QModelIndex &index, int role) const 0359 { 0360 if (!index.isValid()) 0361 return QVariant(); 0362 0363 Q_D(const AlternativeItemsModel); 0364 AltNode *n = static_cast<AltNode *>(index.internalPointer()); 0365 if (AltItemNode *n_i = altnode_cast<AltItemNode>(n)) 0366 { 0367 switch (role) 0368 { 0369 case Qt::DisplayRole: 0370 return n_i->item->getName(); 0371 case Qt::ToolTipRole: 0372 { 0373 QString tip = n_i->item->getName(); 0374 if (n_i->item->isBroken()) 0375 { 0376 tip += "\n\n"; 0377 tip += i18n("Broken alternative group."); 0378 } 0379 return tip; 0380 } 0381 case Qt::ForegroundRole: 0382 if (d->isChanged(n_i)) 0383 return QColor(Qt::red); 0384 break; 0385 case Qt::FontRole: 0386 if (d->isChanged(n_i)) 0387 { 0388 QFont f; 0389 f.setBold(true); 0390 return f; 0391 } 0392 break; 0393 case Qt::DecorationRole: 0394 if (n_i->item->isBroken()) 0395 return d->brokenAltIcon; 0396 break; 0397 case AltItemRole: 0398 return QVariant::fromValue(n_i->item); 0399 } 0400 } 0401 return QVariant(); 0402 } 0403 0404 Qt::ItemFlags AlternativeItemsModel::flags(const QModelIndex &index) const 0405 { 0406 if (!index.isValid()) 0407 return Qt::NoItemFlags; 0408 0409 AltNode *n = static_cast<AltNode *>(index.internalPointer()); 0410 if (AltItemNode *n_i = altnode_cast<AltItemNode>(n)) 0411 { 0412 Qt::ItemFlags f = Qt::ItemIsSelectable; 0413 if (!n_i->item->isBroken()) 0414 f |= Qt::ItemIsEnabled; 0415 return f; 0416 } 0417 return Qt::NoItemFlags; 0418 } 0419 0420 bool AlternativeItemsModel::hasChildren(const QModelIndex &parent) const 0421 { 0422 return parent.isValid() ? false : AlternativesBaseModel::hasChildren(parent); 0423 } 0424 0425 QVariant AlternativeItemsModel::headerData(int section, Qt::Orientation orientation, int role) const 0426 { 0427 if (orientation != Qt::Horizontal) 0428 return QVariant(); 0429 0430 switch (role) 0431 { 0432 case Qt::DisplayRole: 0433 if (section == 0) 0434 return i18nc("Groups of alternatives", "Groups"); 0435 break; 0436 } 0437 return QVariant(); 0438 } 0439 0440 QModelIndex AlternativeItemsModel::index(int row, int column, const QModelIndex &parent) const 0441 { 0442 return parent.isValid() ? QModelIndex() : AlternativesBaseModel::index(row, column, parent); 0443 } 0444 0445 int AlternativeItemsModel::rowCount(const QModelIndex &parent) const 0446 { 0447 return parent.isValid() ? 0 : AlternativesBaseModel::rowCount(parent); 0448 } 0449 0450 void AlternativeItemsModel::save() 0451 { 0452 Q_D(AlternativeItemsModel); 0453 if (!d->altManager) 0454 return; 0455 0456 QModelIndexList changedIndexes; 0457 const int rows = d->m_root.m_children.count(); 0458 for (int i = 0; i < rows; ++i) 0459 { 0460 AltItemNode *node = d->m_root.m_children.at(i); 0461 Item *item = node->item; 0462 bool itemChanged = false; 0463 0464 if (node->changed) 0465 { 0466 int index = 0; 0467 AltAlternativeNode* altnode = d->findSelectedAlternative(node, &index); 0468 Q_ASSERT(altnode); 0469 QString selectError; 0470 if (!altnode->alternative->select(&selectError)) 0471 { 0472 qCDebug(KALT_LOG) << selectError << Qt::endl; 0473 return; 0474 } 0475 node->changed = false; 0476 itemChanged = true; 0477 } 0478 if (node->nbrAltChanged || node->modeChanged) 0479 { 0480 QString parentPath = d->altManager->getAltDir() + '/' + item->getName(); 0481 0482 QFile origFile(parentPath); 0483 if (origFile.exists()) 0484 { 0485 origFile.remove(); 0486 } 0487 0488 if (origFile.open(QIODevice::WriteOnly)) 0489 { 0490 QTextStream stream(&origFile); 0491 0492 stream << Item::modeString(item->getMode()) << Qt::endl; 0493 stream << item->getPath() << Qt::endl; 0494 0495 SlaveList *slaveList = item->getSlaves(); 0496 Q_FOREACH (Slave *slave, *slaveList) 0497 { 0498 stream << slave->slname << Qt::endl; 0499 stream << slave->slpath << Qt::endl; 0500 } 0501 0502 stream << Qt::endl; 0503 0504 AltsPtrList *altItemList = item->getAlternatives(); 0505 Q_FOREACH (Alternative *a, *altItemList) 0506 { 0507 stream << a->getPath() << Qt::endl; 0508 stream << a->getPriority() << Qt::endl; 0509 0510 Q_FOREACH (const QString &slave, a->getSlaves()) 0511 { 0512 stream << slave << Qt::endl; 0513 } 0514 } 0515 0516 stream << Qt::endl; 0517 0518 origFile.close(); 0519 } 0520 node->nbrAltChanged = false; 0521 node->modeChanged = false; 0522 itemChanged = true; 0523 } 0524 if (itemChanged) 0525 { 0526 changedIndexes.append(createIndex(i, 0, node)); 0527 } 0528 } 0529 Q_FOREACH (const QModelIndex &index, changedIndexes) 0530 { 0531 emit dataChanged(index, index); 0532 } 0533 } 0534 0535 bool AlternativeItemsModel::isSupported() const 0536 { 0537 Q_D(const AlternativeItemsModel); 0538 return d->altManager; 0539 } 0540 0541 0542 class AlternativeAltModelPrivate : public AlternativesBaseModelPrivate 0543 { 0544 public: 0545 AlternativeAltModelPrivate(AlternativeItemsModel *itemModel, bool readOnly); 0546 ~AlternativeAltModelPrivate(); 0547 0548 void load() Q_DECL_OVERRIDE; 0549 AltNode* root() const Q_DECL_OVERRIDE { return m_root; } 0550 0551 Q_DECLARE_PUBLIC(AlternativeAltModel) 0552 0553 AltAlternativeNode* findHigherPriority(int *index) const; 0554 void searchDescription(Alternative *alternative) const; 0555 0556 void statusChanged(int index); 0557 0558 AlternativeItemsModelPrivate *parentModel; 0559 AltItemNode m_nullRoot; 0560 AltItemNode *m_root; 0561 bool m_readOnly; 0562 }; 0563 0564 AlternativeAltModelPrivate::AlternativeAltModelPrivate(AlternativeItemsModel *itemModel, bool readOnly) 0565 : AlternativesBaseModelPrivate() 0566 , parentModel(itemModel->d_func()), m_nullRoot(Q_NULLPTR, 0), m_root(&m_nullRoot), m_readOnly(readOnly) 0567 { 0568 } 0569 0570 AlternativeAltModelPrivate::~AlternativeAltModelPrivate() 0571 { 0572 } 0573 0574 void AlternativeAltModelPrivate::load() 0575 { 0576 } 0577 0578 AltAlternativeNode* AlternativeAltModelPrivate::findHigherPriority(int *index) const 0579 { 0580 const int num = m_root->m_children.count(); 0581 if (!num) 0582 { 0583 *index = 0; 0584 return Q_NULLPTR; 0585 } 0586 0587 int id = 0; 0588 AltAlternativeNode* n = m_root->m_children.at(id); 0589 int priority = n->alternative->getPriority(); 0590 for (int i = 1; i < num; ++i) 0591 { 0592 AltAlternativeNode* tmp = m_root->m_children.at(i); 0593 if (tmp->alternative->getPriority() > priority) 0594 { 0595 id = i; 0596 n = tmp; 0597 priority = n->alternative->getPriority(); 0598 } 0599 } 0600 *index = id; 0601 return n; 0602 } 0603 0604 static bool extractDescriptionFor(const QString &outputLine, const QString &name, QString *desc) 0605 { 0606 QString output = outputLine; 0607 int pos = output.indexOf('('); 0608 // look for the name of the search result, and discard it 0609 // in case it is not exactly what we requested 0610 if (pos == -1 || (output.left(pos -1) != name)) 0611 return false; 0612 0613 pos = output.indexOf(']'); 0614 if (pos != -1) 0615 { 0616 output.remove(0, pos + 1); 0617 } 0618 pos = output.indexOf(')'); 0619 if (pos != -1) 0620 { 0621 output.remove(0, pos + 1); 0622 } 0623 pos = output.indexOf('-'); 0624 if (pos != -1) 0625 { 0626 output.remove(0, pos + 2); 0627 } 0628 *desc = output; 0629 return true; 0630 } 0631 0632 void AlternativeAltModelPrivate::searchDescription(Alternative *alternative) const 0633 { 0634 QString exec = alternative->getPath(); 0635 const int slashPos = exec.lastIndexOf('/'); 0636 if (slashPos != -1) 0637 exec.remove(0, slashPos + 1); 0638 0639 KProcess proc; 0640 proc.setProgram("whatis", QStringList() << exec); 0641 proc.setOutputChannelMode(KProcess::SeparateChannels); 0642 proc.setEnv("COLUMNS", QString::number(300)); 0643 proc.start(); 0644 proc.waitForStarted(); 0645 proc.waitForFinished(); 0646 if (proc.exitCode() == 0) 0647 { 0648 const QByteArray procOutput = proc.readAllStandardOutput(); 0649 const QStringList outputLines = QString::fromLocal8Bit(procOutput.constData()).split('\n', Qt::SkipEmptyParts); 0650 Q_FOREACH (const QString &outLine, outputLines) 0651 { 0652 QString description; 0653 if (extractDescriptionFor(outLine, exec, &description)) 0654 { 0655 alternative->setDescription(description); 0656 break; 0657 } 0658 } 0659 } 0660 } 0661 0662 void AlternativeAltModelPrivate::statusChanged(int index) 0663 { 0664 if (m_root == &m_nullRoot) 0665 return; 0666 0667 Q_Q(AlternativeAltModel); 0668 QComboBox *combo = q->sender() ? qobject_cast<QComboBox *>(q->sender()) : Q_NULLPTR; 0669 if (!combo) 0670 return; 0671 0672 const Item::ItemMode mode = static_cast<Item::ItemMode>(combo->itemData(index).toInt()); 0673 m_root->item->setMode(mode); 0674 ItemChanges changes = ModeItemChange; 0675 if (mode == Item::AutoMode) 0676 { 0677 int selectedIndex = 0; 0678 int higherPriorityIndex = 0; 0679 AltAlternativeNode *selectedaltnode = parentModel->findSelectedAlternative(m_root, &selectedIndex); 0680 AltAlternativeNode *newaltnode = findHigherPriority(&higherPriorityIndex); 0681 if (selectedIndex != higherPriorityIndex) 0682 { 0683 QModelIndexList indexes; 0684 selectedaltnode->selected = false; 0685 indexes.append(q->createIndex(selectedIndex, 0, selectedaltnode)); 0686 newaltnode->selected = true; 0687 indexes.append(q->createIndex(higherPriorityIndex, 0, newaltnode)); 0688 m_root->changed = true; 0689 Q_FOREACH (const QModelIndex &index, indexes) 0690 { 0691 emit q->dataChanged(index, index); 0692 } 0693 changes |= SelectionItemChange; 0694 } 0695 } 0696 parentModel->itemChanged(m_root, changes); 0697 } 0698 0699 0700 AlternativeAltModel::AlternativeAltModel(AlternativeItemsModel *itemModel, bool readOnly, QObject *parent) 0701 : AlternativesBaseModel(*new AlternativeAltModelPrivate(itemModel, readOnly), parent) 0702 { 0703 } 0704 0705 AlternativeAltModel::~AlternativeAltModel() 0706 { 0707 } 0708 0709 int AlternativeAltModel::columnCount(const QModelIndex &parent) const 0710 { 0711 Q_UNUSED(parent) 0712 return 3; 0713 } 0714 0715 QVariant AlternativeAltModel::data(const QModelIndex &index, int role) const 0716 { 0717 if (!index.isValid()) 0718 return QVariant(); 0719 0720 Q_D(const AlternativeAltModel); 0721 AltNode *n = static_cast<AltNode *>(index.internalPointer()); 0722 if (AltAlternativeNode *n_a = altnode_cast<AltAlternativeNode>(n)) 0723 { 0724 switch (role) 0725 { 0726 case Qt::DisplayRole: 0727 { 0728 switch (index.column()) 0729 { 0730 case 0: 0731 return n_a->alternative->getPath(); 0732 case 1: 0733 return n_a->alternative->getPriority(); 0734 case 2: 0735 if (n_a->alternative->getDescription().isEmpty()) 0736 d->searchDescription(n_a->alternative); 0737 return Alternative::prettyDescription(n_a->alternative); 0738 } 0739 break; 0740 } 0741 case Qt::ToolTipRole: 0742 { 0743 if (n_a->alternative->getDescription().isEmpty()) 0744 d->searchDescription(n_a->alternative); 0745 KLocalizedString tip = n_a->alternative->isBroken() 0746 ? ki18nc("%1 is the alternative path, %2 its description", 0747 "%1\n(broken)\n\n%2") 0748 : ki18nc("%1 is the alternative path, %2 its description", 0749 "%1\n\n%2"); 0750 return tip.subs(n_a->alternative->getPath()) 0751 .subs(Alternative::prettyDescription(n_a->alternative)) 0752 .toString(); 0753 } 0754 case Qt::EditRole: 0755 if (index.column() == 0) 0756 return n_a->selected; 0757 break; 0758 case Qt::CheckStateRole: 0759 if (index.column() == 0) 0760 return n_a->selected ? Qt::Checked : Qt::Unchecked; 0761 break; 0762 case Qt::DecorationRole: 0763 if (index.column() == 0 && n_a->alternative->isBroken()) 0764 return d->parentModel->brokenAltIcon; 0765 break; 0766 case AltAlternativeRole: 0767 return QVariant::fromValue(n_a->alternative); 0768 } 0769 } 0770 return QVariant(); 0771 } 0772 0773 Qt::ItemFlags AlternativeAltModel::flags(const QModelIndex &index) const 0774 { 0775 if (!index.isValid()) 0776 return Qt::NoItemFlags; 0777 0778 Q_D(const AlternativeAltModel); 0779 AltNode *n = static_cast<AltNode *>(index.internalPointer()); 0780 if (AltAlternativeNode *n_a = altnode_cast<AltAlternativeNode>(n)) 0781 { 0782 Qt::ItemFlags f = Qt::ItemIsSelectable; 0783 if (!n_a->alternative->isBroken()) 0784 f |= Qt::ItemIsEnabled; 0785 switch (index.column()) 0786 { 0787 case 0: 0788 return f | Qt::ItemIsUserCheckable; 0789 default: 0790 return f; 0791 } 0792 } 0793 return Qt::NoItemFlags; 0794 } 0795 0796 QVariant AlternativeAltModel::headerData(int section, Qt::Orientation orientation, int role) const 0797 { 0798 if (orientation != Qt::Horizontal) 0799 return QVariant(); 0800 0801 switch (role) 0802 { 0803 case Qt::DisplayRole: 0804 switch (section) 0805 { 0806 case 0: 0807 return i18n("Option"); 0808 case 1: 0809 return i18n("Priority"); 0810 case 2: 0811 return i18n("Description"); 0812 } 0813 break; 0814 } 0815 return QVariant(); 0816 } 0817 0818 QModelIndex AlternativeAltModel::parent(const QModelIndex &index) const 0819 { 0820 Q_UNUSED(index); 0821 return QModelIndex(); 0822 } 0823 0824 bool AlternativeAltModel::setData(const QModelIndex &index, const QVariant &value, int role) 0825 { 0826 if (!index.isValid()) 0827 return false; 0828 0829 AltAlternativeNode *n = altnode_cast<AltAlternativeNode>(static_cast<AltNode *>(index.internalPointer())); 0830 if (!n) 0831 return false; 0832 0833 Q_D(AlternativeAltModel); 0834 switch (role) 0835 { 0836 case Qt::CheckStateRole: 0837 { 0838 if (d->m_readOnly || n->alternative->isBroken()) 0839 break; 0840 0841 const bool newValue = value.toBool(); 0842 if (newValue) 0843 { 0844 if (!n->selected) 0845 { 0846 QModelIndexList changedIndexes; 0847 Q_FOREACH (AltAlternativeNode* node, d->m_root->m_children) 0848 { 0849 if (node->selected) 0850 { 0851 node->selected = false; 0852 changedIndexes.append(d->indexForItem(node, index.column())); 0853 } 0854 } 0855 n->selected = true; 0856 changedIndexes.append(index); 0857 Q_FOREACH (const QModelIndex &changedIndex, changedIndexes) 0858 { 0859 emit dataChanged(changedIndex, changedIndex); 0860 } 0861 ItemChanges changes = SelectionItemChange; 0862 // when changing option, set the alternative to "manual" mode 0863 if (d->m_root->item->getMode() == Item::AutoMode) 0864 { 0865 d->m_root->item->setMode(Item::ManualMode); 0866 changes |= ModeItemChange; 0867 } 0868 d->parentModel->itemChanged(d->m_root, changes); 0869 return true; 0870 } 0871 } 0872 break; 0873 } 0874 } 0875 return false; 0876 } 0877 0878 void AlternativeAltModel::setItem(Item *item) 0879 { 0880 Q_D(AlternativeAltModel); 0881 beginResetModel(); 0882 d->m_root = &d->m_nullRoot; 0883 Q_FOREACH (AltItemNode *n, d->parentModel->m_root.m_children) 0884 { 0885 if (n->item == item) 0886 { 0887 d->m_root = n; 0888 break; 0889 } 0890 } 0891 if (d->m_root->item) 0892 { 0893 d->parentModel->loadItemNode(d->m_root); 0894 } 0895 endResetModel(); 0896 } 0897 0898 void AlternativeAltModel::addAlternative(Alternative *alt) 0899 { 0900 if (!alt) 0901 return; 0902 0903 Q_D(AlternativeAltModel); 0904 if (alt->getParent() != d->m_root->item) 0905 return; 0906 0907 const int childCount = d->m_root->m_children.count(); 0908 beginInsertRows(QModelIndex(), childCount, childCount); 0909 d->m_root->item->addAlternative(alt); 0910 d->m_root->m_children.append(new AltAlternativeNode(alt, d->m_root)); 0911 endInsertRows(); 0912 d->parentModel->itemChanged(d->m_root, AltNumItemChange); 0913 } 0914 0915 void AlternativeAltModel::removeAlternative(Alternative *alt) 0916 { 0917 if (!alt) 0918 return; 0919 0920 Q_D(AlternativeAltModel); 0921 if (alt->getParent() != d->m_root->item) 0922 return; 0923 0924 int altId = 0; 0925 const int childCount = d->m_root->m_children.count(); 0926 for ( ; altId < childCount; ++altId) 0927 { 0928 if (d->m_root->m_children.at(altId)->alternative == alt) 0929 break; 0930 } 0931 if (altId == childCount) 0932 return; 0933 0934 const bool wasSelected = d->m_root->m_children.at(altId)->selected; 0935 beginRemoveRows(QModelIndex(), altId, altId); 0936 d->m_root->item->delAlternativeByPath(alt->getPath()); 0937 delete d->m_root->m_children.at(altId); 0938 d->m_root->m_children.removeAt(altId); 0939 endRemoveRows(); 0940 if (wasSelected && !d->m_root->m_children.isEmpty()) 0941 { 0942 int row = 0; 0943 AltAlternativeNode *node = d->findHigherPriority(&row); 0944 node->selected = true; 0945 const QModelIndex changedIndex = createIndex(row, 0, node); 0946 emit dataChanged(changedIndex, changedIndex); 0947 } 0948 d->parentModel->itemChanged(d->m_root, AltNumItemChange); 0949 } 0950 0951 0952 AlternativeItemProxyModel::AlternativeItemProxyModel(QObject *parent) 0953 : QSortFilterProxyModel(parent), m_showSingle(false) 0954 { 0955 } 0956 0957 AlternativeItemProxyModel::~AlternativeItemProxyModel() 0958 { 0959 } 0960 0961 void AlternativeItemProxyModel::setShowSingleAlternative(bool show) 0962 { 0963 if (show == m_showSingle) 0964 return; 0965 0966 m_showSingle = show; 0967 invalidateFilter(); 0968 } 0969 0970 bool AlternativeItemProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const 0971 { 0972 Item *item = sourceModel()->index(source_row, 0, source_parent).data(AltItemRole).value<Item *>(); 0973 return !item || m_showSingle || item->countAlternatives() > 1; 0974 } 0975 0976 #include <moc_alternativemodels.cpp>