| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "QCMakeCacheView.h" | |
| #include <QApplication> | |
| #include <QEvent> | |
| #include <QHBoxLayout> | |
| #include <QHeaderView> | |
| #include <QKeyEvent> | |
| #include <QMetaProperty> | |
| #include <QSortFilterProxyModel> | |
| #include <QStyle> | |
| #include "QCMakeSizeType.h" | |
| #include "QCMakeWidgets.h" | |
| // filter for searches | |
| class QCMakeSearchFilter : public QSortFilterProxyModel | |
| { | |
| public: | |
| QCMakeSearchFilter(QObject* o) | |
| : QSortFilterProxyModel(o) | |
| { | |
| } | |
| protected: | |
| bool filterAcceptsRow(int row, QModelIndex const& p) const override | |
| { | |
| QStringList strs; | |
| QAbstractItemModel const* m = this->sourceModel(); | |
| QModelIndex idx = m->index(row, 0, p); | |
| // if there are no children, get strings for column 0 and 1 | |
| if (!m->hasChildren(idx)) { | |
| strs.append(m->data(idx).toString()); | |
| idx = m->index(row, 1, p); | |
| strs.append(m->data(idx).toString()); | |
| } else { | |
| // get strings for children entries to compare with | |
| // instead of comparing with the parent | |
| int num = m->rowCount(idx); | |
| for (int i = 0; i < num; i++) { | |
| QModelIndex tmpidx = m->index(i, 0, idx); | |
| strs.append(m->data(tmpidx).toString()); | |
| tmpidx = m->index(i, 1, idx); | |
| strs.append(m->data(tmpidx).toString()); | |
| } | |
| } | |
| // check all strings for a match | |
| foreach (QString const& str, strs) { | |
| #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) | |
| if (str.contains(this->filterRegularExpression())) { | |
| #else | |
| if (str.contains(this->filterRegExp())) { | |
| #endif | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| }; | |
| // filter for searches | |
| class QCMakeAdvancedFilter : public QSortFilterProxyModel | |
| { | |
| public: | |
| QCMakeAdvancedFilter(QObject* o) | |
| : QSortFilterProxyModel(o) | |
| { | |
| } | |
| void setShowAdvanced(bool f) | |
| { | |
| this->ShowAdvanced = f; | |
| this->invalidate(); | |
| } | |
| bool showAdvanced() const { return this->ShowAdvanced; } | |
| protected: | |
| bool ShowAdvanced = false; | |
| bool filterAcceptsRow(int row, QModelIndex const& p) const override | |
| { | |
| QAbstractItemModel const* m = this->sourceModel(); | |
| QModelIndex idx = m->index(row, 0, p); | |
| // if there are no children | |
| if (!m->hasChildren(idx)) { | |
| bool adv = m->data(idx, QCMakeCacheModel::AdvancedRole).toBool(); | |
| return !adv || this->ShowAdvanced; | |
| } | |
| // check children | |
| int num = m->rowCount(idx); | |
| for (int i = 0; i < num; i++) { | |
| bool accept = this->filterAcceptsRow(i, idx); | |
| if (accept) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| }; | |
| QCMakeCacheView::QCMakeCacheView(QWidget* p) | |
| : QTreeView(p) | |
| { | |
| // hook up our model and search/filter proxies | |
| this->CacheModel = new QCMakeCacheModel(this); | |
| this->AdvancedFilter = new QCMakeAdvancedFilter(this); | |
| this->AdvancedFilter->setSourceModel(this->CacheModel); | |
| this->AdvancedFilter->setDynamicSortFilter(true); | |
| this->SearchFilter = new QCMakeSearchFilter(this); | |
| this->SearchFilter->setSourceModel(this->AdvancedFilter); | |
| this->SearchFilter->setFilterCaseSensitivity(Qt::CaseInsensitive); | |
| this->SearchFilter->setDynamicSortFilter(true); | |
| this->setModel(this->SearchFilter); | |
| // our delegate for creating our editors | |
| QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this); | |
| this->setItemDelegate(delegate); | |
| this->setUniformRowHeights(true); | |
| this->setEditTriggers(QAbstractItemView::AllEditTriggers); | |
| // tab, backtab doesn't step through items | |
| this->setTabKeyNavigation(false); | |
| this->setRootIsDecorated(false); | |
| } | |
| bool QCMakeCacheView::event(QEvent* e) | |
| { | |
| if (e->type() == QEvent::Show) { | |
| this->header()->setDefaultSectionSize(this->viewport()->width() / 2); | |
| } | |
| return QTreeView::event(e); | |
| } | |
| QCMakeCacheModel* QCMakeCacheView::cacheModel() const | |
| { | |
| return this->CacheModel; | |
| } | |
| QModelIndex QCMakeCacheView::moveCursor(CursorAction act, | |
| Qt::KeyboardModifiers mod) | |
| { | |
| // want home/end to go to begin/end of rows, not columns | |
| if (act == MoveHome) { | |
| return this->model()->index(0, 1); | |
| } | |
| if (act == MoveEnd) { | |
| return this->model()->index(this->model()->rowCount() - 1, 1); | |
| } | |
| return QTreeView::moveCursor(act, mod); | |
| } | |
| void QCMakeCacheView::setShowAdvanced(bool s) | |
| { | |
| this->SearchFilter->invalidate(); | |
| this->AdvancedFilter->setShowAdvanced(s); | |
| } | |
| bool QCMakeCacheView::showAdvanced() const | |
| { | |
| return this->AdvancedFilter->showAdvanced(); | |
| } | |
| bool QCMakeCacheView::setSearchFilter(QString const& s) | |
| { | |
| return QtCMake::setSearchFilter(this->SearchFilter, s); | |
| } | |
| QCMakeCacheModel::QCMakeCacheModel(QObject* p) | |
| : QStandardItemModel(p) | |
| , EditEnabled(true) | |
| , NewPropertyCount(0) | |
| , View(FlatView) | |
| { | |
| this->ShowNewProperties = true; | |
| QStringList labels; | |
| labels << tr("Name") << tr("Value"); | |
| this->setHorizontalHeaderLabels(labels); | |
| } | |
| QCMakeCacheModel::~QCMakeCacheModel() = default; | |
| static size_t qHash(QCMakeProperty const& p) | |
| { | |
| return qHash(p.Key); | |
| } | |
| void QCMakeCacheModel::setShowNewProperties(bool f) | |
| { | |
| this->ShowNewProperties = f; | |
| } | |
| void QCMakeCacheModel::clear() | |
| { | |
| this->QStandardItemModel::clear(); | |
| this->NewPropertyCount = 0; | |
| QStringList labels; | |
| labels << tr("Name") << tr("Value"); | |
| this->setHorizontalHeaderLabels(labels); | |
| } | |
| void QCMakeCacheModel::setProperties(QCMakePropertyList const& props) | |
| { | |
| this->beginResetModel(); | |
| QSet<QCMakeProperty> newProps; | |
| QSet<QCMakeProperty> newProps2; | |
| if (this->ShowNewProperties) { | |
| #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) | |
| newProps = props.toSet(); | |
| #else | |
| newProps = QSet<QCMakeProperty>(props.begin(), props.end()); | |
| #endif | |
| newProps2 = newProps; | |
| #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) | |
| QSet<QCMakeProperty> oldProps = this->properties().toSet(); | |
| #else | |
| QCMakePropertyList const& oldPropsList = this->properties(); | |
| QSet<QCMakeProperty> oldProps = | |
| QSet<QCMakeProperty>(oldPropsList.begin(), oldPropsList.end()); | |
| #endif | |
| oldProps.intersect(newProps); | |
| newProps.subtract(oldProps); | |
| newProps2.subtract(newProps); | |
| } else { | |
| #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) | |
| newProps2 = props.toSet(); | |
| #else | |
| newProps2 = QSet<QCMakeProperty>(props.begin(), props.end()); | |
| #endif | |
| } | |
| bool b = this->blockSignals(true); | |
| // Empty the model. Avoid QStandardItemModel::clear(), because that calls | |
| // beginResetModel() internally, and we can't nest such calls. | |
| this->removeRows(0, this->rowCount()); | |
| this->NewPropertyCount = newProps.size(); | |
| if (View == FlatView) { | |
| QCMakePropertyList newP = newProps.values(); | |
| QCMakePropertyList newP2 = newProps2.values(); | |
| #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) | |
| std::sort(newP.begin(), newP.end()); | |
| std::sort(newP2.begin(), newP2.end()); | |
| #else | |
| qSort(newP); | |
| qSort(newP2); | |
| #endif | |
| int row_count = 0; | |
| foreach (QCMakeProperty const& p, newP) { | |
| this->insertRow(row_count); | |
| this->setPropertyData(this->index(row_count, 0), p, true); | |
| row_count++; | |
| } | |
| foreach (QCMakeProperty const& p, newP2) { | |
| this->insertRow(row_count); | |
| this->setPropertyData(this->index(row_count, 0), p, false); | |
| row_count++; | |
| } | |
| } else if (this->View == GroupView) { | |
| QMap<QString, QCMakePropertyList> newPropsTree; | |
| QCMakeCacheModel::breakProperties(newProps, newPropsTree); | |
| QMap<QString, QCMakePropertyList> newPropsTree2; | |
| QCMakeCacheModel::breakProperties(newProps2, newPropsTree2); | |
| QStandardItem* root = this->invisibleRootItem(); | |
| for (QMap<QString, QCMakePropertyList>::const_iterator iter = | |
| newPropsTree.begin(); | |
| iter != newPropsTree.end(); ++iter) { | |
| QString const& key = iter.key(); | |
| QCMakePropertyList const& props2 = iter.value(); | |
| QList<QStandardItem*> parentItems; | |
| parentItems.append( | |
| new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key)); | |
| parentItems.append(new QStandardItem()); | |
| #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) | |
| parentItems[0]->setData(QBrush(QColor(255, 100, 100)), | |
| Qt::BackgroundRole); | |
| parentItems[1]->setData(QBrush(QColor(255, 100, 100)), | |
| Qt::BackgroundRole); | |
| #else | |
| parentItems[0]->setData(QBrush(QColor(255, 100, 100)), | |
| Qt::BackgroundColorRole); | |
| parentItems[1]->setData(QBrush(QColor(255, 100, 100)), | |
| Qt::BackgroundColorRole); | |
| #endif | |
| parentItems[0]->setData(1, GroupRole); | |
| parentItems[1]->setData(1, GroupRole); | |
| root->appendRow(parentItems); | |
| cm_qsizetype num = props2.size(); | |
| for (cm_qsizetype i = 0; i < num; i++) { | |
| QCMakeProperty const& prop = props2[i]; | |
| QList<QStandardItem*> items; | |
| items.append(new QStandardItem()); | |
| items.append(new QStandardItem()); | |
| parentItems[0]->appendRow(items); | |
| this->setPropertyData(this->indexFromItem(items[0]), prop, true); | |
| } | |
| } | |
| for (QMap<QString, QCMakePropertyList>::const_iterator iter = | |
| newPropsTree2.begin(); | |
| iter != newPropsTree2.end(); ++iter) { | |
| QString const& key = iter.key(); | |
| QCMakePropertyList const& props2 = iter.value(); | |
| QStandardItem* parentItem = | |
| new QStandardItem(key.isEmpty() ? tr("Ungrouped Entries") : key); | |
| root->appendRow(parentItem); | |
| parentItem->setData(1, GroupRole); | |
| cm_qsizetype num = props2.size(); | |
| for (cm_qsizetype i = 0; i < num; i++) { | |
| QCMakeProperty const& prop = props2[i]; | |
| QList<QStandardItem*> items; | |
| items.append(new QStandardItem()); | |
| items.append(new QStandardItem()); | |
| parentItem->appendRow(items); | |
| this->setPropertyData(this->indexFromItem(items[0]), prop, false); | |
| } | |
| } | |
| } | |
| this->blockSignals(b); | |
| this->endResetModel(); | |
| } | |
| QCMakeCacheModel::ViewType QCMakeCacheModel::viewType() const | |
| { | |
| return this->View; | |
| } | |
| void QCMakeCacheModel::setViewType(QCMakeCacheModel::ViewType t) | |
| { | |
| this->View = t; | |
| QCMakePropertyList props = this->properties(); | |
| QCMakePropertyList oldProps; | |
| cm_qsizetype numNew = this->NewPropertyCount; | |
| cm_qsizetype numTotal = props.count(); | |
| for (cm_qsizetype i = numNew; i < numTotal; i++) { | |
| oldProps.append(props[i]); | |
| } | |
| bool b = this->blockSignals(true); | |
| this->clear(); | |
| this->setProperties(oldProps); | |
| this->setProperties(props); | |
| this->blockSignals(b); | |
| } | |
| void QCMakeCacheModel::setPropertyData(QModelIndex const& idx1, | |
| QCMakeProperty const& prop, bool isNew) | |
| { | |
| QModelIndex idx2 = idx1.sibling(idx1.row(), 1); | |
| this->setData(idx1, prop.Key, Qt::DisplayRole); | |
| this->setData(idx1, prop.Help, QCMakeCacheModel::HelpRole); | |
| this->setData(idx1, prop.Type, QCMakeCacheModel::TypeRole); | |
| this->setData(idx1, prop.Advanced, QCMakeCacheModel::AdvancedRole); | |
| if (prop.Type == QCMakeProperty::BOOL) { | |
| int check = prop.Value.toBool() ? Qt::Checked : Qt::Unchecked; | |
| this->setData(idx2, check, Qt::CheckStateRole); | |
| } else { | |
| this->setData(idx2, prop.Value, Qt::DisplayRole); | |
| } | |
| this->setData(idx2, prop.Help, QCMakeCacheModel::HelpRole); | |
| if (!prop.Strings.isEmpty()) { | |
| this->setData(idx1, prop.Strings, QCMakeCacheModel::StringsRole); | |
| } | |
| if (isNew) { | |
| #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) | |
| this->setData(idx1, QBrush(QColor(255, 100, 100)), Qt::BackgroundRole); | |
| this->setData(idx2, QBrush(QColor(255, 100, 100)), Qt::BackgroundRole); | |
| #else | |
| this->setData(idx1, QBrush(QColor(255, 100, 100)), | |
| Qt::BackgroundColorRole); | |
| this->setData(idx2, QBrush(QColor(255, 100, 100)), | |
| Qt::BackgroundColorRole); | |
| #endif | |
| } | |
| } | |
| void QCMakeCacheModel::getPropertyData(QModelIndex const& idx1, | |
| QCMakeProperty& prop) const | |
| { | |
| QModelIndex idx2 = idx1.sibling(idx1.row(), 1); | |
| prop.Key = this->data(idx1, Qt::DisplayRole).toString(); | |
| prop.Help = this->data(idx1, HelpRole).toString(); | |
| prop.Type = static_cast<QCMakeProperty::PropertyType>( | |
| this->data(idx1, TypeRole).toInt()); | |
| prop.Advanced = this->data(idx1, AdvancedRole).toBool(); | |
| prop.Strings = | |
| this->data(idx1, QCMakeCacheModel::StringsRole).toStringList(); | |
| if (prop.Type == QCMakeProperty::BOOL) { | |
| int check = this->data(idx2, Qt::CheckStateRole).toInt(); | |
| prop.Value = check == Qt::Checked; | |
| } else { | |
| prop.Value = this->data(idx2, Qt::DisplayRole).toString(); | |
| } | |
| } | |
| QString QCMakeCacheModel::prefix(QString const& s) | |
| { | |
| QString prefix = s.section('_', 0, 0); | |
| if (prefix == s) { | |
| prefix = QString(); | |
| } | |
| return prefix; | |
| } | |
| void QCMakeCacheModel::breakProperties( | |
| QSet<QCMakeProperty> const& props, QMap<QString, QCMakePropertyList>& result) | |
| { | |
| QMap<QString, QCMakePropertyList> tmp; | |
| // return a map of properties grouped by prefixes, and sorted | |
| foreach (QCMakeProperty const& p, props) { | |
| QString prefix = QCMakeCacheModel::prefix(p.Key); | |
| tmp[prefix].append(p); | |
| } | |
| // sort it and re-org any properties with only one sub item | |
| QCMakePropertyList reorgProps; | |
| QMap<QString, QCMakePropertyList>::iterator iter; | |
| for (iter = tmp.begin(); iter != tmp.end();) { | |
| if (iter->count() == 1) { | |
| reorgProps.append((*iter)[0]); | |
| iter = tmp.erase(iter); | |
| } else { | |
| #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) | |
| std::sort(iter->begin(), iter->end()); | |
| #else | |
| qSort(*iter); | |
| #endif | |
| ++iter; | |
| } | |
| } | |
| if (reorgProps.count()) { | |
| tmp[QString()] += reorgProps; | |
| } | |
| result = tmp; | |
| } | |
| QCMakePropertyList QCMakeCacheModel::properties() const | |
| { | |
| QCMakePropertyList props; | |
| if (!this->rowCount()) { | |
| return props; | |
| } | |
| QVector<QModelIndex> idxs; | |
| idxs.append(this->index(0, 0)); | |
| // walk the entire model for property entries | |
| // this works regardless of a flat view or a tree view | |
| while (!idxs.isEmpty()) { | |
| QModelIndex idx = idxs.last(); | |
| if (this->hasChildren(idx) && this->rowCount(idx)) { | |
| idxs.append(this->index(0, 0, idx)); | |
| } else { | |
| if (!data(idx, GroupRole).toInt()) { | |
| // get data | |
| QCMakeProperty prop; | |
| this->getPropertyData(idx, prop); | |
| props.append(prop); | |
| } | |
| // go to the next in the tree | |
| while (!idxs.isEmpty() && | |
| ( | |
| #if QT_VERSION < QT_VERSION_CHECK(5, 1, 0) | |
| (idxs.last().row() + 1) >= rowCount(idxs.last().parent()) || | |
| #endif | |
| !idxs.last().sibling(idxs.last().row() + 1, 0).isValid())) { | |
| idxs.remove(idxs.size() - 1); | |
| } | |
| if (!idxs.isEmpty()) { | |
| idxs.last() = idxs.last().sibling(idxs.last().row() + 1, 0); | |
| } | |
| } | |
| } | |
| return props; | |
| } | |
| bool QCMakeCacheModel::insertProperty(QCMakeProperty::PropertyType t, | |
| QString const& name, | |
| QString const& description, | |
| QVariant const& value, bool advanced) | |
| { | |
| QCMakeProperty prop; | |
| prop.Key = name; | |
| prop.Value = value; | |
| prop.Help = description; | |
| prop.Type = t; | |
| prop.Advanced = advanced; | |
| // insert at beginning | |
| this->insertRow(0); | |
| this->setPropertyData(this->index(0, 0), prop, true); | |
| this->NewPropertyCount++; | |
| return true; | |
| } | |
| void QCMakeCacheModel::setEditEnabled(bool e) | |
| { | |
| this->EditEnabled = e; | |
| } | |
| bool QCMakeCacheModel::editEnabled() const | |
| { | |
| return this->EditEnabled; | |
| } | |
| cm_qsizetype QCMakeCacheModel::newPropertyCount() const | |
| { | |
| return this->NewPropertyCount; | |
| } | |
| Qt::ItemFlags QCMakeCacheModel::flags(QModelIndex const& idx) const | |
| { | |
| Qt::ItemFlags f = QStandardItemModel::flags(idx); | |
| if (!this->EditEnabled) { | |
| f &= ~Qt::ItemIsEditable; | |
| return f; | |
| } | |
| if (QCMakeProperty::BOOL == this->data(idx, TypeRole).toInt()) { | |
| f |= Qt::ItemIsUserCheckable; | |
| } | |
| return f; | |
| } | |
| QModelIndex QCMakeCacheModel::buddy(QModelIndex const& idx) const | |
| { | |
| if (!this->hasChildren(idx) && | |
| this->data(idx, TypeRole).toInt() != QCMakeProperty::BOOL) { | |
| return this->index(idx.row(), 1, idx.parent()); | |
| } | |
| return idx; | |
| } | |
| QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p) | |
| : QItemDelegate(p) | |
| , FileDialogFlag(false) | |
| { | |
| } | |
| void QCMakeCacheModelDelegate::setFileDialogFlag(bool f) | |
| { | |
| this->FileDialogFlag = f; | |
| } | |
| QWidget* QCMakeCacheModelDelegate::createEditor( | |
| QWidget* p, QStyleOptionViewItem const& /*option*/, | |
| QModelIndex const& idx) const | |
| { | |
| QModelIndex var = idx.sibling(idx.row(), 0); | |
| int type = var.data(QCMakeCacheModel::TypeRole).toInt(); | |
| if (type == QCMakeProperty::BOOL) { | |
| return nullptr; | |
| } | |
| if (type == QCMakeProperty::PATH) { | |
| QCMakePathEditor* editor = | |
| new QCMakePathEditor(p, var.data(Qt::DisplayRole).toString()); | |
| QObject::connect(editor, &QCMakePathEditor::fileDialogExists, this, | |
| &QCMakeCacheModelDelegate::setFileDialogFlag); | |
| return editor; | |
| } | |
| if (type == QCMakeProperty::FILEPATH) { | |
| QCMakeFilePathEditor* editor = | |
| new QCMakeFilePathEditor(p, var.data(Qt::DisplayRole).toString()); | |
| QObject::connect(editor, &QCMakePathEditor::fileDialogExists, this, | |
| &QCMakeCacheModelDelegate::setFileDialogFlag); | |
| return editor; | |
| } | |
| if (type == QCMakeProperty::STRING && | |
| var.data(QCMakeCacheModel::StringsRole).isValid()) { | |
| QCMakeComboBox* editor = new QCMakeComboBox( | |
| p, var.data(QCMakeCacheModel::StringsRole).toStringList()); | |
| editor->setFrame(false); | |
| return editor; | |
| } | |
| QLineEdit* editor = new QLineEdit(p); | |
| editor->setFrame(false); | |
| return editor; | |
| } | |
| bool QCMakeCacheModelDelegate::editorEvent(QEvent* e, | |
| QAbstractItemModel* model, | |
| QStyleOptionViewItem const& option, | |
| QModelIndex const& index) | |
| { | |
| Qt::ItemFlags flags = model->flags(index); | |
| if (!(flags & Qt::ItemIsUserCheckable) || | |
| !(option.state & QStyle::State_Enabled) || | |
| !(flags & Qt::ItemIsEnabled)) { | |
| return false; | |
| } | |
| QVariant value = index.data(Qt::CheckStateRole); | |
| if (!value.isValid()) { | |
| return false; | |
| } | |
| if ((e->type() == QEvent::MouseButtonRelease) || | |
| (e->type() == QEvent::MouseButtonDblClick)) { | |
| // eat the double click events inside the check rect | |
| if (e->type() == QEvent::MouseButtonDblClick) { | |
| return true; | |
| } | |
| } else if (e->type() == QEvent::KeyPress) { | |
| if (static_cast<QKeyEvent*>(e)->key() != Qt::Key_Space && | |
| static_cast<QKeyEvent*>(e)->key() != Qt::Key_Select) { | |
| return false; | |
| } | |
| } else { | |
| return false; | |
| } | |
| Qt::CheckState state = | |
| (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked ? Qt::Unchecked | |
| : Qt::Checked); | |
| bool success = model->setData(index, state, Qt::CheckStateRole); | |
| if (success) { | |
| this->recordChange(model, index); | |
| } | |
| return success; | |
| } | |
| bool QCMakeCacheModelDelegate::eventFilter(QObject* object, QEvent* evt) | |
| { | |
| // FIXME: This filter avoids a crash when opening a file dialog | |
| // with the '...' button on a cache entry line in the GUI. | |
| // Previously this filter was commented as a workaround for Qt issue 205903, | |
| // but that was fixed in Qt 4.5.0 and the crash still occurs as of Qt 5.14 | |
| // without this filter. This needs further investigation. | |
| if (evt->type() == QEvent::FocusOut && this->FileDialogFlag) { | |
| return false; | |
| } | |
| return QItemDelegate::eventFilter(object, evt); | |
| } | |
| void QCMakeCacheModelDelegate::setModelData(QWidget* editor, | |
| QAbstractItemModel* model, | |
| QModelIndex const& index) const | |
| { | |
| QItemDelegate::setModelData(editor, model, index); | |
| const_cast<QCMakeCacheModelDelegate*>(this)->recordChange(model, index); | |
| } | |
| QSize QCMakeCacheModelDelegate::sizeHint(QStyleOptionViewItem const& option, | |
| QModelIndex const& index) const | |
| { | |
| QSize sz = QItemDelegate::sizeHint(option, index); | |
| QStyle* style = QApplication::style(); | |
| // increase to checkbox size | |
| QStyleOptionButton opt; | |
| opt.QStyleOption::operator=(option); | |
| #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) | |
| sz = sz.expandedTo( | |
| style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, nullptr) | |
| .size()); | |
| #else | |
| sz = sz.expandedTo( | |
| style->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, nullptr) | |
| .size()); | |
| #endif | |
| return sz; | |
| } | |
| QSet<QCMakeProperty> QCMakeCacheModelDelegate::changes() const | |
| { | |
| return mChanges; | |
| } | |
| void QCMakeCacheModelDelegate::clearChanges() | |
| { | |
| mChanges.clear(); | |
| } | |
| void QCMakeCacheModelDelegate::recordChange(QAbstractItemModel* model, | |
| QModelIndex const& index) | |
| { | |
| QModelIndex idx = index; | |
| QAbstractItemModel* mymodel = model; | |
| while (qobject_cast<QAbstractProxyModel*>(mymodel)) { | |
| idx = static_cast<QAbstractProxyModel*>(mymodel)->mapToSource(idx); | |
| mymodel = static_cast<QAbstractProxyModel*>(mymodel)->sourceModel(); | |
| } | |
| QCMakeCacheModel* cache_model = qobject_cast<QCMakeCacheModel*>(mymodel); | |
| if (cache_model && idx.isValid()) { | |
| QCMakeProperty prop; | |
| idx = idx.sibling(idx.row(), 0); | |
| cache_model->getPropertyData(idx, prop); | |
| // clean out an old one | |
| QSet<QCMakeProperty>::iterator iter = mChanges.find(prop); | |
| if (iter != mChanges.end()) { | |
| mChanges.erase(iter); | |
| } | |
| // now add the new item | |
| mChanges.insert(prop); | |
| } | |
| } |