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:
parent
edaeee168d
commit
abed208efb
2 changed files with 289 additions and 0 deletions
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue