1
0
Fork 0
forked from len0rd/rockbox

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 <amaury.pouly@gmail.com>
This commit is contained in:
Amaury Pouly 2014-10-22 17:59:57 +02:00
parent edaeee168d
commit abed208efb
2 changed files with 289 additions and 0 deletions

View file

@ -427,6 +427,229 @@ QByteArray SocFieldCachedEditorCreator::valuePropertyName() const
return QByteArray("value"); 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("<error>");
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 * RegSexyDisplay
*/ */

View file

@ -201,6 +201,72 @@ public:
protected: 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 class RegSexyDisplay : public QWidget
{ {
Q_OBJECT Q_OBJECT