From abed208efbba78b502c94408b0c9b97c8ab61e14 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Wed, 22 Oct 2014 17:59:57 +0200 Subject: regtools/qeditor: introduce custom table model for reg fields This one is much more efficient than using a generic table widget. Change-Id: I3578964eead746e656f6b0a8dcec0f8442deb13d Reviewed-on: http://gerrit.rockbox.org/1022 Reviewed-by: Amaury Pouly --- utils/regtools/qeditor/utils.cpp | 223 +++++++++++++++++++++++++++++++++++++++ utils/regtools/qeditor/utils.h | 66 ++++++++++++ 2 files changed, 289 insertions(+) (limited to 'utils/regtools/qeditor') diff --git a/utils/regtools/qeditor/utils.cpp b/utils/regtools/qeditor/utils.cpp index 098a020c8e..df7f714f03 100644 --- a/utils/regtools/qeditor/utils.cpp +++ b/utils/regtools/qeditor/utils.cpp @@ -427,6 +427,229 @@ QByteArray SocFieldCachedEditorCreator::valuePropertyName() const return QByteArray("value"); } +/** + * RegFieldTableModel + */ + +RegFieldTableModel::RegFieldTableModel(QObject *parent) + :QAbstractTableModel(parent) +{ + m_read_only = true; +} + +int RegFieldTableModel::rowCount(const QModelIndex& /* parent */) const +{ + return m_reg.field.size(); +} + +int RegFieldTableModel::columnCount(const QModelIndex& /* parent */) const +{ + return ColumnCountOffset + m_value.size(); +} + +QVariant RegFieldTableModel::data(const QModelIndex& index, int role) const +{ + int section = index.column(); + const soc_reg_field_t& field = m_reg.field[index.row()]; + /* column independent code */ + const RegThemeGroup *theme = 0; + switch(m_status[index.row()]) + { + case Normal: theme = &m_theme.normal; break; + case Diff: theme = &m_theme.diff; break; + case Error: theme = &m_theme.error; break; + case None: default: break; + } + if(role == Qt::FontRole) + return theme ? QVariant(theme->font) : QVariant(); + if(role == Qt::BackgroundRole) + return theme ? QVariant(theme->background) : QVariant(); + if(role == Qt::ForegroundRole) + return theme ? QVariant(theme->foreground) : QVariant(); + /* column dependent code */ + if(section == BitRangeColumn) + { + if(role == Qt::DisplayRole) + { + if(field.first_bit == field.last_bit) + return QVariant(QString("%1").arg(field.first_bit)); + else + return QVariant(QString("%1:%2").arg(field.last_bit).arg(field.first_bit)); + } + else if(role == Qt::TextAlignmentRole) + return QVariant(Qt::AlignVCenter | Qt::AlignHCenter); + else + return QVariant(); + } + if(section == NameColumn) + { + if(role == Qt::DisplayRole) + return QVariant(QString::fromStdString(field.name)); + else + return QVariant(); + } + if(section < FirstValueColumn + m_value.size()) + { + int idx = section - FirstValueColumn; + if(role == Qt::DisplayRole) + { + if(!m_value[idx].isValid()) + return QVariant(""); + return QVariant::fromValue(SocFieldCachedValue(field, + field.extract(m_value[idx].value< soc_word_t >()))); + } + else if(role == Qt::EditRole) + { + if(!m_value[idx].isValid()) + return QVariant(); + return QVariant::fromValue(SocFieldCachedValue(field, + field.extract(m_value[idx].value< soc_word_t >()))); + } + else if(role == Qt::TextAlignmentRole) + return QVariant(Qt::AlignVCenter | Qt::AlignHCenter); + else + return QVariant(); + } + section -= m_value.size(); + if(section == DescColumnOffset) + { + if(role == Qt::DisplayRole) + return QVariant(QString::fromStdString(field.desc)); + else + return QVariant(); + } + return QVariant(); +} + +bool RegFieldTableModel::setData(const QModelIndex& idx, const QVariant& value, int role) +{ + if(role != Qt::EditRole) + return false; + int section = idx.column(); + if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size()) + return false; + section -= FirstValueColumn; + const SocFieldCachedValue& v = value.value< SocFieldCachedValue >(); + if(!m_value[section].isValid()) + return false; + soc_word_t old_val = m_value[section].value< soc_word_t >(); + m_value[section] = QVariant(v.field().replace(old_val, v.value())); + // update column + RecomputeTheme(); + emit dataChanged(index(0, section), index(rowCount() - 1, section)); + emit OnValueModified(section); + return true; +} + +Qt::ItemFlags RegFieldTableModel::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + int section = index.column(); + if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size()) + return flags; + section -= FirstValueColumn; + if(m_value[section].isValid() && !m_read_only) + flags |= Qt::ItemIsEditable; + return flags; +} + +QVariant RegFieldTableModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if(orientation == Qt::Vertical) + return QVariant(); + if(role != Qt::DisplayRole) + return QVariant(); + if(section == BitRangeColumn) + return QVariant("Bits"); + if(section == NameColumn) + return QVariant("Name"); + if(section < FirstValueColumn + m_value.size()) + { + int idx = section - FirstValueColumn; + if(m_value.size() == 1) + return QVariant("Value"); + else + return QVariant(QString("Value %1").arg((QChar)('A' + idx))); + } + section -= m_value.size(); + if(section == DescColumnOffset) + return QVariant("Description"); + return QVariant(); +} + +void RegFieldTableModel::SetReadOnly(bool en) +{ + if(en == m_read_only) + return; + m_read_only = en; +} + +void RegFieldTableModel::SetRegister(const soc_reg_t& reg) +{ + /* remove all rows */ + beginRemoveRows(QModelIndex(), 0, rowCount() - 1); + m_reg.field.clear(); + endRemoveRows(); + /* add them all */ + beginInsertRows(QModelIndex(), 0, reg.field.size() - 1); + m_reg = reg; + RecomputeTheme(); + endInsertRows(); +} + +void RegFieldTableModel::SetValues(const QVector< QVariant >& values) +{ + /* remove all value columns */ + beginRemoveColumns(QModelIndex(), FirstValueColumn, + FirstValueColumn + m_value.size() - 1); + m_value.clear(); + endRemoveColumns(); + /* add them back */ + beginInsertColumns(QModelIndex(), FirstValueColumn, + FirstValueColumn + values.size() - 1); + m_value = values; + RecomputeTheme(); + endInsertColumns(); +} + +QVariant RegFieldTableModel::GetValue(int index) +{ + return m_value[index]; +} + +void RegFieldTableModel::SetTheme(const RegTheme& theme) +{ + m_theme = theme; + RecomputeTheme(); + emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); +} + +void RegFieldTableModel::RecomputeTheme() +{ + m_status.resize(m_reg.field.size()); + for(size_t i = 0; i < m_reg.field.size(); i++) + { + m_status[i] = None; + if(!m_theme.valid || m_value.size() == 0) + continue; + m_status[i] = Normal; + const soc_reg_field_t& field = m_reg.field[i]; + QVariant val; + for(int j = 0; j < m_value.size(); j++) + { + QVariant val2 = m_value[j]; + if(!val2.isValid()) + continue; + val2 = QVariant(field.extract(val2.value< soc_word_t >())); + if(!val.isValid()) + val = val2; + else if(val != val2) + m_status[i] = Diff; + } + } +} + /** * RegSexyDisplay */ diff --git a/utils/regtools/qeditor/utils.h b/utils/regtools/qeditor/utils.h index 771b671b2c..da9638baf7 100644 --- a/utils/regtools/qeditor/utils.h +++ b/utils/regtools/qeditor/utils.h @@ -201,6 +201,72 @@ public: protected: }; +struct RegThemeGroup +{ + QBrush foreground; + QBrush background; + QFont font; +}; + +struct RegTheme +{ + RegTheme():valid(false) {} + bool valid; + RegThemeGroup normal; + RegThemeGroup diff; + RegThemeGroup error; +}; + +class RegFieldTableModel : public QAbstractTableModel +{ + Q_OBJECT +public: + RegFieldTableModel(QObject *parent); + virtual int rowCount(const QModelIndex & parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex & parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex & index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual Qt::ItemFlags flags (const QModelIndex & index) const; + virtual bool setData(const QModelIndex& index, const QVariant& value, int role); + + void SetRegister(const soc_reg_t& reg); + /* values can either be an invalid QVariant() (means no value/error), or a + * QVariant containing a soc_word_t */ + void SetValues(const QVector< QVariant >& values); + QVariant GetValue(int index); + void SetTheme(const RegTheme& theme); + void SetReadOnly(bool en); + +signals: + void OnValueModified(int index); + +protected: + void RecomputeTheme(); + + enum + { + BitRangeColumn = 0, + NameColumn, + FirstValueColumn, + DescColumnOffset = FirstValueColumn, /* offset from nr_values */ + ColumnCountOffset, /* offset from nr_values */ + }; + + enum ColorStatus + { + None, + Normal, + Diff, + Error + }; + + soc_reg_t m_reg; + QVector< QVariant > m_value; + QVector< ColorStatus > m_status; + RegTheme m_theme; + bool m_read_only; +}; + class RegSexyDisplay : public QWidget { Q_OBJECT -- cgit v1.2.3