diff options
author | Clinton Stimpson <clinton@elemtech.com> | 2008-06-10 04:17:00 (GMT) |
---|---|---|
committer | Clinton Stimpson <clinton@elemtech.com> | 2008-06-10 04:17:00 (GMT) |
commit | 13d55b6ae4e5d618893f7ae82136828c3bc754b1 (patch) | |
tree | 4c1e35095e29c349acd73ca0ca575e0a5346068f /Source | |
parent | 1ee52bb29bdc646308967a5033c3de2b7d96ac91 (diff) | |
download | CMake-13d55b6ae4e5d618893f7ae82136828c3bc754b1.zip CMake-13d55b6ae4e5d618893f7ae82136828c3bc754b1.tar.gz CMake-13d55b6ae4e5d618893f7ae82136828c3bc754b1.tar.bz2 |
ENH: Use a tree view of the properties instead of a flat list view.
Properties are grouped by a prefix (up to first "_") and can be expanded
or collapsed.
Fixes #6359.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/QtDialog/CMakeSetupDialog.cxx | 30 | ||||
-rw-r--r-- | Source/QtDialog/CMakeSetupDialog.ui | 2 | ||||
-rw-r--r-- | Source/QtDialog/QCMakeCacheView.cxx | 485 | ||||
-rw-r--r-- | Source/QtDialog/QCMakeCacheView.h | 57 |
4 files changed, 417 insertions, 157 deletions
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 3eda31d..6330a15 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -300,7 +300,7 @@ void CMakeSetupDialog::doConfigure() void CMakeSetupDialog::finishConfigure(int err) { - if(0 == err && 0 == this->CacheValues->cacheModel()->newCount()) + if(0 == err && !this->CacheValues->cacheModel()->hasNewProperties()) { this->enterState(ReadyGenerate); } @@ -559,20 +559,20 @@ bool CMakeSetupDialog::setupFirstConfigure() QString fortranCompiler = dialog.getFortranCompiler(); if(!fortranCompiler.isEmpty()) { - m->insertProperty(0, QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER", + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER", "Fortran compiler.", fortranCompiler, false); } QString cxxCompiler = dialog.getCXXCompiler(); if(!cxxCompiler.isEmpty()) { - m->insertProperty(0, QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER", + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER", "CXX compiler.", cxxCompiler, false); } QString cCompiler = dialog.getCCompiler(); if(!cCompiler.isEmpty()) { - m->insertProperty(0, QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER", + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER", "C compiler.", cCompiler, false); } } @@ -581,7 +581,7 @@ bool CMakeSetupDialog::setupFirstConfigure() QString toolchainFile = dialog.crossCompilerToolChainFile(); if(!toolchainFile.isEmpty()) { - m->insertProperty(0, QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE", + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_TOOLCHAIN_FILE", "Cross Compile ToolChain File", toolchainFile, false); } else @@ -589,32 +589,32 @@ bool CMakeSetupDialog::setupFirstConfigure() QString fortranCompiler = dialog.getFortranCompiler(); if(!fortranCompiler.isEmpty()) { - m->insertProperty(0, QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER", + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_Fortran_COMPILER", "Fortran compiler.", fortranCompiler, false); } QString mode = dialog.getCrossIncludeMode(); - m->insertProperty(0, QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE", + m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE", "CMake Find Include Mode", mode, false); mode = dialog.getCrossLibraryMode(); - m->insertProperty(0, QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY", + m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY", "CMake Find Library Mode", mode, false); mode = dialog.getCrossProgramMode(); - m->insertProperty(0, QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM", + m->insertProperty(QCMakeProperty::STRING, "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM", "CMake Find Program Mode", mode, false); QString rootPath = dialog.getCrossRoot(); - m->insertProperty(0, QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH", + m->insertProperty(QCMakeProperty::PATH, "CMAKE_FIND_ROOT_PATH", "CMake Find Root Path", rootPath, false); QString systemName = dialog.getSystemName(); - m->insertProperty(0, QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME", + m->insertProperty(QCMakeProperty::STRING, "CMAKE_SYSTEM_NAME", "CMake System Name", systemName, false); QString cxxCompiler = dialog.getCXXCompiler(); - m->insertProperty(0, QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER", + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_CXX_COMPILER", "CXX compiler.", cxxCompiler, false); QString cCompiler = dialog.getCCompiler(); - m->insertProperty(0, QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER", + m->insertProperty(QCMakeProperty::FILEPATH, "CMAKE_C_COMPILER", "C compiler.", cCompiler, false); } } @@ -808,7 +808,7 @@ void CMakeSetupDialog::removeSelectedCacheEntries() } foreach(QPersistentModelIndex pi, pidxs) { - this->CacheValues->model()->removeRow(pi.row()); + this->CacheValues->model()->removeRow(pi.row(), pi.parent()); } } @@ -897,7 +897,7 @@ void CMakeSetupDialog::addCacheEntry() if(QDialog::Accepted == dialog.exec()) { QCMakeCacheModel* m = this->CacheValues->cacheModel(); - m->insertProperty(0, w->type(), w->name(), w->description(), w->value(), false); + m->insertProperty(w->type(), w->name(), w->description(), w->value(), false); } } diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui index 12984b2..3f68555 100644 --- a/Source/QtDialog/CMakeSetupDialog.ui +++ b/Source/QtDialog/CMakeSetupDialog.ui @@ -295,7 +295,7 @@ <customwidgets> <customwidget> <class>QCMakeCacheView</class> - <extends>QTableView</extends> + <extends>QTreeView</extends> <header>QCMakeCacheView.h</header> </customwidget> </customwidgets> diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx index 245de8e..24cbc2b 100644 --- a/Source/QtDialog/QCMakeCacheView.cxx +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -36,19 +36,46 @@ public: protected: bool filterAcceptsRow(int row, const QModelIndex& p) const { - // accept row if either column matches - QModelIndex idx0 = this->sourceModel()->index(row, 0, p); - QModelIndex idx1 = this->sourceModel()->index(row, 1, p); - QString str0 = this->sourceModel()->data(idx0).toString(); - QString str1 = this->sourceModel()->data(idx1).toString(); + QStringList strs; + const QAbstractItemModel* m = this->sourceModel(); + QModelIndex idx = m->index(row, 0, p); - return str0.contains(this->filterRegExp()) || - str1.contains(this->filterRegExp()); + // 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 str, strs) + { + if(str.contains(this->filterRegExp())) + { + return true; + } + } + + return false; } }; QCMakeCacheView::QCMakeCacheView(QWidget* p) - : QTableView(p), Init(false) + : QTreeView(p), Init(false) { // hook up our model and search/filter proxies this->CacheModel = new QCMakeCacheModel(this); @@ -79,9 +106,7 @@ QCMakeCacheView::QCMakeCacheView(QWidget* p) int h = 0; QFontMetrics met(this->font()); h = qMax(met.height(), this->style()->pixelMetric(QStyle::PM_IndicatorHeight)); - this->verticalHeader()->setDefaultSectionSize(h + 4); - this->horizontalHeader()->setStretchLastSection(true); - this->verticalHeader()->hide(); + this->header()->setDefaultSectionSize(h + 4); } void QCMakeCacheView::showEvent(QShowEvent* e) @@ -94,7 +119,7 @@ void QCMakeCacheView::showEvent(QShowEvent* e) this->setColumnWidth(1, colWidth/2); this->Init = true; } - return QTableView::showEvent(e); + return QTreeView::showEvent(e); } QCMakeCacheModel* QCMakeCacheView::cacheModel() const @@ -114,7 +139,7 @@ QModelIndex QCMakeCacheView::moveCursor(CursorAction act, { return this->model()->index(this->model()->rowCount()-1, 1); } - return QTableView::moveCursor(act, mod); + return QTreeView::moveCursor(act, mod); } void QCMakeCacheView::setShowAdvanced(bool s) @@ -134,8 +159,8 @@ void QCMakeCacheView::setSearchFilter(const QString& s) } QCMakeCacheModel::QCMakeCacheModel(QObject* p) - : QAbstractTableModel(p), - NewCount(0), EditEnabled(true) + : QAbstractItemModel(p), + EditEnabled(true) { } @@ -156,55 +181,139 @@ void QCMakeCacheModel::clear() void QCMakeCacheModel::setProperties(const QCMakePropertyList& props) { QSet<QCMakeProperty> newProps = props.toSet(); - QSet<QCMakeProperty> newProps2 = props.toSet(); - QSet<QCMakeProperty> oldProps = this->Properties.toSet(); + QSet<QCMakeProperty> newProps2 = newProps; + QSet<QCMakeProperty> oldProps = this->properties().toSet(); oldProps.intersect(newProps); newProps.subtract(oldProps); newProps2.subtract(newProps); - this->NewCount = newProps.count(); this->Properties.clear(); + this->NewProperties.clear(); - this->Properties = newProps.toList(); - qSort(this->Properties); - QCMakePropertyList tmp = newProps2.toList(); - qSort(tmp); - this->Properties += tmp; - + QMap<QString, QCMakePropertyList> result; + this->breakProperties(newProps, result); + foreach(QString key, result.keys()) + { + this->NewProperties.append(QPair<QString, QCMakePropertyList>(key, result.value(key))); + } + result.clear(); + this->breakProperties(newProps2, result); + foreach(QString key, result.keys()) + { + this->Properties.append(QPair<QString, QCMakePropertyList>(key, result.value(key))); + } + + // tell everyone to discard whatever they knew (cached) about this model this->reset(); } + +QString QCMakeCacheModel::prefix(const QString& s) +{ + QString prefix = s.section('_', 0, 0); + return prefix; +} + +void QCMakeCacheModel::breakProperties(const QSet<QCMakeProperty>& props, + QMap<QString, QCMakePropertyList>& result) +{ + // return a map of properties grouped by prefixes, and sorted + foreach(QCMakeProperty p, props) + { + QString prefix = QCMakeCacheModel::prefix(p.Key); + result[prefix].append(p); + } + QMap<QString, QCMakePropertyList>::iterator iter; + for(iter = result.begin(); iter != result.end(); ++iter) + { + qSort(*iter); + } +} QCMakePropertyList QCMakeCacheModel::properties() const { - return this->Properties; + QCMakePropertyList props; + QPair<QString, QCMakePropertyList> l; + foreach(l, this->NewProperties) + { + props += l.second; + } + foreach(l, this->Properties) + { + props += l.second; + } + return props; } -bool QCMakeCacheModel::insertProperty(int row, QCMakeProperty::PropertyType t, +bool QCMakeCacheModel::insertProperty(QCMakeProperty::PropertyType t, const QString& name, const QString& description, const QVariant& value, bool advanced) { - if(this->insertRows(row, 1, QModelIndex())) + QCMakeProperty prop; + prop.Key = name; + prop.Value = value; + prop.Help = description; + prop.Type = t; + prop.Advanced = advanced; + + // find where to insert it in the new properties section + QString prefix = this->prefix(name); + QList<QPair<QString, QCMakePropertyList> >::iterator iter = this->NewProperties.begin(); + while(iter != this->NewProperties.end() && prefix > iter->first) { - QModelIndex idx1 = this->index(row, 0); - QModelIndex idx2 = this->index(row, 1); - - this->setData(idx1, t, QCMakeCacheModel::TypeRole); - this->setData(idx1, name, Qt::DisplayRole); - this->setData(idx1, description, QCMakeCacheModel::HelpRole); - this->setData(idx1, advanced, QCMakeCacheModel::AdvancedRole); - if(t == QCMakeProperty::BOOL) + ++iter; + } + + bool insertedParent = false; + + // insert a new parent item for this group of properties with this prefix + // if there isn't one + if(iter == this->NewProperties.end() || iter->first != prefix) + { + int row = iter - this->NewProperties.begin(); + this->beginInsertRows(QModelIndex(), row, row); + iter = this->NewProperties.insert(iter, QPair<QString, QCMakePropertyList>(prefix, QCMakePropertyList())); + insertedParent = true; + } + + // find where to insert the property in the group of properties + QCMakePropertyList::iterator jter = iter->second.begin(); + while(jter != iter->second.end() && name > jter->Key) + { + ++jter; + } + + QModelIndex idxp = this->index(iter - this->NewProperties.begin(), 0); + + if(jter != iter->second.end() && jter->Key == name) + { + // replace existing item + *jter = prop; + QModelIndex idx1 = this->index(jter - iter->second.begin(), 0, idxp); + QModelIndex idx2 = this->index(jter - iter->second.begin(), 1, idxp); + this->dataChanged(idx1, idx2); + } + else + { + // add new item + int row = jter - iter->second.begin(); + if(!insertedParent) { - this->setData(idx2, value.toBool() ? Qt::Checked : Qt::Unchecked, - Qt::CheckStateRole); + this->beginInsertRows(idxp, row, row); } - else + jter = iter->second.insert(jter, prop); + if(!insertedParent) { - this->setData(idx2, value, Qt::DisplayRole); + this->endInsertRows(); } - return true; } - return false; + + if(insertedParent) + { + this->endInsertRows(); + } + + return true; } void QCMakeCacheModel::setEditEnabled(bool e) @@ -217,9 +326,9 @@ bool QCMakeCacheModel::editEnabled() const return this->EditEnabled; } -int QCMakeCacheModel::newCount() const +bool QCMakeCacheModel::hasNewProperties() const { - return this->NewCount; + return !this->NewProperties.isEmpty(); } int QCMakeCacheModel::columnCount (const QModelIndex& /*p*/ ) const @@ -227,62 +336,177 @@ int QCMakeCacheModel::columnCount (const QModelIndex& /*p*/ ) const return 2; } -QVariant QCMakeCacheModel::data (const QModelIndex& idx, int role) const +bool QCMakeCacheModel::isNewProperty(const QModelIndex& idx) const { - if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) + if(idx.isValid() && idx.internalId()) { - return this->Properties[idx.row()].Key; + return (idx.internalId() - 1) < this->NewProperties.count(); } - else if(idx.column() == 0 && role == Qt::ToolTipRole) + else if(idx.isValid()) { - return this->data(idx, Qt::DisplayRole).toString() + "\n" + - this->data(idx, QCMakeCacheModel::HelpRole).toString(); + return idx.row() < this->NewProperties.count(); } - else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole)) + return false; +} + +const QCMakeProperty* QCMakeCacheModel::propertyForIndex(const QModelIndex& idx) const +{ + const QPair<QString, QCMakePropertyList>* l = this->propertyListForIndex(idx); + if(l && idx.internalId()) { - if(this->Properties[idx.row()].Type != QCMakeProperty::BOOL) + if(idx.row() < l->second.count()) { - return this->Properties[idx.row()].Value; + return &l->second[idx.row()]; } } - else if(idx.column() == 1 && role == Qt::CheckStateRole) + return NULL; +} + +const QPair<QString, QCMakePropertyList>* QCMakeCacheModel::propertyListForIndex(const QModelIndex& idx) const +{ + int row = -1; + if(idx.isValid() && idx.internalId() > 0) { - if(this->Properties[idx.row()].Type == QCMakeProperty::BOOL) - { - return this->Properties[idx.row()].Value.toBool() ? Qt::Checked : Qt::Unchecked; - } + row = idx.internalId() - 1; } - else if(role == QCMakeCacheModel::HelpRole) + else if(idx.isValid()) { - return this->Properties[idx.row()].Help; + row = idx.row(); } - else if(role == QCMakeCacheModel::TypeRole) + if(row != -1) { - return this->Properties[idx.row()].Type; + if(row < this->NewProperties.count()) + { + return &this->NewProperties[row]; + } + row -= this->NewProperties.count(); + if(row < this->Properties.count()) + { + return &this->Properties[row]; + } } - else if(role == QCMakeCacheModel::AdvancedRole) + return NULL; +} + +QVariant QCMakeCacheModel::data (const QModelIndex& idx, int role) const +{ + const QPair<QString, QCMakePropertyList>* l = this->propertyListForIndex(idx); + const QCMakeProperty* p = propertyForIndex(idx); + if(l && !p) { - return this->Properties[idx.row()].Advanced; + if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) + { + return l->first; + } + else if(role == QCMakeCacheModel::AdvancedRole) + { + // return true if all subitems are advanced + foreach(QCMakeProperty p, l->second) + { + if(!p.Advanced) + { + return false; + } + } + return true; + } + } + if(l && p) + { + if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) + { + return p->Key; + } + else if(idx.column() == 0 && role == Qt::ToolTipRole) + { + return p->Key + "\n" + p->Help; + } + else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole)) + { + if(p->Type != QCMakeProperty::BOOL) + { + return p->Value; + } + } + else if(idx.column() == 1 && role == Qt::CheckStateRole) + { + if(p->Type == QCMakeProperty::BOOL) + { + return p->Value.toBool() ? Qt::Checked : Qt::Unchecked; + } + } + else if(role == QCMakeCacheModel::HelpRole) + { + return p->Help; + } + else if(role == QCMakeCacheModel::TypeRole) + { + return p->Type; + } + else if(role == QCMakeCacheModel::AdvancedRole) + { + return p->Advanced; + } } - else if(role == Qt::BackgroundRole && idx.row()+1 <= this->NewCount) + + if(role == Qt::BackgroundRole && this->isNewProperty(idx)) { return QBrush(QColor(255,100,100)); } + return QVariant(); } -QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*idx*/) const +QModelIndex QCMakeCacheModel::parent (const QModelIndex& idx) const +{ + if(idx.isValid() && idx.internalId()) + { + return this->createIndex(idx.internalId()-1, 0); + } + return QModelIndex(); +} + +QModelIndex QCMakeCacheModel::index (int row, int column, const QModelIndex& idx) const { + if(!idx.isValid() && row < this->rowCount(idx) && column < this->columnCount(idx)) + { + // index at root level + return this->createIndex(row, column); + } + else if(idx.isValid() && !idx.internalId() && row < this->rowCount(idx) && column < this->columnCount(idx)) + { + // index at sub-item + return this->createIndex(row, column, idx.row()+1); + } return QModelIndex(); } -int QCMakeCacheModel::rowCount (const QModelIndex& p) const +bool QCMakeCacheModel::hasChildren (const QModelIndex& idx) const +{ + if(idx.isValid() && idx.internalId()) + { + return false; + } + return true; +} + +int QCMakeCacheModel::rowCount (const QModelIndex& idx) const { - if(p.isValid()) + if(!idx.isValid()) + { + int num = this->Properties.count() + this->NewProperties.count(); + return num; + } + + const QPair<QString, QCMakePropertyList>* l = this->propertyListForIndex(idx); + const QCMakeProperty* p = this->propertyForIndex(idx); + + if(l && !p) { - return 0; + return l->second.count(); } - return this->Properties.count(); + + return 0; } QVariant QCMakeCacheModel::headerData (int section, Qt::Orientation orient, int role) const @@ -298,12 +522,14 @@ QVariant QCMakeCacheModel::headerData (int section, Qt::Orientation orient, int Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& idx) const { Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + const QCMakeProperty* p = this->propertyForIndex(idx); + // all column 1's are editable - if(idx.column() == 1 && this->EditEnabled) + if(p && idx.column() == 1 && this->EditEnabled) { f |= Qt::ItemIsEditable; // booleans are editable in place - if(this->Properties[idx.row()].Type == QCMakeProperty::BOOL) + if(p->Type == QCMakeProperty::BOOL) { f |= Qt::ItemIsUserCheckable; } @@ -314,86 +540,83 @@ Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& idx) const bool QCMakeCacheModel::setData (const QModelIndex& idx, const QVariant& value, int role) { - if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) - { - this->Properties[idx.row()].Key = value.toString(); - emit this->dataChanged(idx, idx); - } - else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole)) + QCMakeProperty* p = const_cast<QCMakeProperty*>(this->propertyForIndex(idx)); + if(p) { - this->Properties[idx.row()].Value = value.toString(); - emit this->dataChanged(idx, idx); - } - else if(idx.column() == 1 && (role == Qt::CheckStateRole)) - { - this->Properties[idx.row()].Value = value.toInt() == Qt::Checked; - emit this->dataChanged(idx, idx); - } - else if(role == QCMakeCacheModel::HelpRole) - { - this->Properties[idx.row()].Help = value.toString(); - emit this->dataChanged(idx, idx); - } - else if(role == QCMakeCacheModel::TypeRole) - { - this->Properties[idx.row()].Type = static_cast<QCMakeProperty::PropertyType>(value.toInt()); - } - else if(role == QCMakeCacheModel::AdvancedRole) - { - this->Properties[idx.row()].Advanced = value.toBool(); + if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole)) + { + p->Value = value.toString(); + emit this->dataChanged(idx, idx); + return true; + } + else if(idx.column() == 1 && (role == Qt::CheckStateRole)) + { + p->Value = value.toInt() == Qt::Checked; + emit this->dataChanged(idx, idx); + return true; + } } return false; } QModelIndex QCMakeCacheModel::buddy(const QModelIndex& idx) const { - if(idx.column() == 0) + const QCMakeProperty* p = this->propertyForIndex(idx); + if(p && idx.column() == 0) { - if(this->Properties[idx.row()].Type != QCMakeProperty::BOOL) + if(p->Type != QCMakeProperty::BOOL) { - return this->index(idx.row(), 1); + return this->index(idx.row(), 1, idx.parent()); } } return idx; } -bool QCMakeCacheModel::removeRows(int row, int num, const QModelIndex&) +bool QCMakeCacheModel::removeRows(int row, int count, const QModelIndex& p) { - if(row < 0 || row+num > this->Properties.count()) - { - return false; - } - this->beginRemoveRows(QModelIndex(), row, row+num-1); - for(int i=0; i<num; i++) + // remove parent items + if(!p.isValid()) { - this->Properties.removeAt(row); - if(this->NewCount >= row+1) + this->beginRemoveRows(p, row, row-1+count); + while(count != 0 && row < this->NewProperties.count()) { - this->NewCount--; + this->NewProperties.removeAt(row); + count--; } + row -= this->NewProperties.count(); + while(count != 0 && row < this->Properties.count()) + { + this->Properties.removeAt(row); + count--; + } + this->endRemoveRows(); + return true; } - this->endRemoveRows(); - return true; -} -bool QCMakeCacheModel::insertRows(int row, int num, const QModelIndex&) -{ - if(row < 0) - row = 0; - if(row > this->rowCount()) - row = this->rowCount(); + // get the parent item containing the item to remove + QPair<QString, QCMakePropertyList>* l = + const_cast<QPair<QString, QCMakePropertyList>*>(this->propertyListForIndex(p)); + if(!l || l->second.count() < row) + { + return false; + } - this->beginInsertRows(QModelIndex(), row, row+num-1); - for(int i=0; i<num; i++) + // all items under parent item are being removed, remove the parent item too + if(l->second.count() == count && row == 0) { - this->Properties.insert(row+i, QCMakeProperty()); - if(this->NewCount >= row) - { - this->NewCount++; - } + return this->removeRows(p.row(), 1, QModelIndex()); } - this->endInsertRows(); - return true; + + // remove the sub items + if(l->second.count() >= count + row) + { + this->beginRemoveRows(p, row, row-1+count); + l->second.erase(l->second.begin()+row, l->second.begin()+row+count); + this->endRemoveRows(); + return true; + } + + return false; } QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p) @@ -484,10 +707,12 @@ bool QCMakeCacheModelDelegate::editorEvent(QEvent* e, QAbstractItemModel* model, bool QCMakeCacheModelDelegate::eventFilter(QObject* object, QEvent* event) { // workaround for what looks like a bug in Qt on Mac OS X + // where it doesn't create a QWidget wrapper for the native file dialog + // so the Qt library ends up assuming the focus was lost to something else if(event->type() == QEvent::FocusOut && this->FileDialogFlag) - { + { return false; - } + } return QItemDelegate::eventFilter(object, event); } diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h index 41b3e1f..301e6c9 100644 --- a/Source/QtDialog/QCMakeCacheView.h +++ b/Source/QtDialog/QCMakeCacheView.h @@ -19,7 +19,7 @@ #define QCMakeCacheView_h #include "QCMake.h" -#include <QTableView> +#include <QTreeView> #include <QAbstractTableModel> #include <QItemDelegate> @@ -28,17 +28,24 @@ class QCMakeCacheModel; /// Qt view class for cache properties -class QCMakeCacheView : public QTableView +class QCMakeCacheView : public QTreeView { Q_OBJECT public: QCMakeCacheView(QWidget* p); + // retrieve the QCMakeCacheModel storing all the pointers + // this isn't necessarily the model one would get from model() QCMakeCacheModel* cacheModel() const; + + // get whether to show advanced entries bool showAdvanced() const; public slots: + // set whether to show advanced entries void setShowAdvanced(bool); + // set the search filter string. any property key or value not matching will + // be filtered out void setSearchFilter(const QString&); protected: @@ -51,30 +58,42 @@ protected: }; /// Qt model class for cache properties -class QCMakeCacheModel : public QAbstractTableModel +class QCMakeCacheModel : public QAbstractItemModel { Q_OBJECT public: QCMakeCacheModel(QObject* parent); ~QCMakeCacheModel(); + // roles used to retrieve extra data such has help strings, types of + // properties, and the advanced flag enum { HelpRole = Qt::UserRole, TypeRole, AdvancedRole }; public slots: + // set a list of properties. This list will be sorted and grouped according + // to prefix. Any property that existed already and which is found in this + // list of properties to set will become an old property. All others will + // become new properties and be marked red. void setProperties(const QCMakePropertyList& props); + + // clear everything from the model void clear(); + + // set flag whether the model can currently be edited. void setEditEnabled(bool); - bool removeRows(int row, int count, const QModelIndex& idx = QModelIndex()); - bool insertRows(int row, int num, const QModelIndex&); + + // remove properties from the model + bool removeRows(int row, int count, const QModelIndex& idx); - // insert a property at a row specifying all the information about the + // insert a new property at a row specifying all the information about the // property - bool insertProperty(int row, QCMakeProperty::PropertyType t, + bool insertProperty(QCMakeProperty::PropertyType t, const QString& name, const QString& description, const QVariant& value, bool advanced); public: // satisfy [pure] virtuals + QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) const; int columnCount (const QModelIndex& parent) const; QVariant data (const QModelIndex& index, int role = Qt::DisplayRole) const; QModelIndex parent (const QModelIndex& index) const; @@ -83,6 +102,7 @@ public: Qt::ItemFlags flags (const QModelIndex& index) const; bool setData (const QModelIndex& index, const QVariant& value, int role); QModelIndex buddy (const QModelIndex& index) const; + bool hasChildren (const QModelIndex& index) const; // get the properties QCMakePropertyList properties() const; @@ -90,12 +110,27 @@ public: // editing enabled bool editEnabled() const; - int newCount() const; - + // returns if there are any new properties + bool hasNewProperties() const; + protected: - QCMakePropertyList Properties; - int NewCount; + QList<QPair<QString, QCMakePropertyList> > NewProperties; + QList<QPair<QString, QCMakePropertyList> > Properties; bool EditEnabled; + + // gets the internal data for a model index, if it exists + const QCMakeProperty* propertyForIndex(const QModelIndex& idx) const; + const QPair<QString,QCMakePropertyList>* propertyListForIndex(const QModelIndex& idx) const; + bool isNewProperty(const QModelIndex& idx) const; + + // breaks up he property list into groups + // where each group has the same prefix up to the first underscore + static void breakProperties(const QSet<QCMakeProperty>& props, + QMap<QString, QCMakePropertyList>& result); + + // gets the prefix of a string up to the first _ + static QString prefix(const QString& s); + }; /// Qt delegate class for interaction (or other customization) |