diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2014-10-22 17:59:57 +0200 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2014-12-15 22:54:28 +0100 |
commit | abed208efbba78b502c94408b0c9b97c8ab61e14 (patch) | |
tree | ccc7c8c575f7b3f45aeb7f9a978755f172a70590 /utils | |
parent | edaeee168df5137c451ce777df431633287bad0a (diff) | |
download | rockbox-abed208efbba78b502c94408b0c9b97c8ab61e14.tar.gz rockbox-abed208efbba78b502c94408b0c9b97c8ab61e14.zip |
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>
Diffstat (limited to 'utils')
-rw-r--r-- | utils/regtools/qeditor/utils.cpp | 223 | ||||
-rw-r--r-- | utils/regtools/qeditor/utils.h | 66 |
2 files changed, 289 insertions, 0 deletions
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 | |||
@@ -428,6 +428,229 @@ QByteArray SocFieldCachedEditorCreator::valuePropertyName() const | |||
428 | } | 428 | } |
429 | 429 | ||
430 | /** | 430 | /** |
431 | * RegFieldTableModel | ||
432 | */ | ||
433 | |||
434 | RegFieldTableModel::RegFieldTableModel(QObject *parent) | ||
435 | :QAbstractTableModel(parent) | ||
436 | { | ||
437 | m_read_only = true; | ||
438 | } | ||
439 | |||
440 | int RegFieldTableModel::rowCount(const QModelIndex& /* parent */) const | ||
441 | { | ||
442 | return m_reg.field.size(); | ||
443 | } | ||
444 | |||
445 | int RegFieldTableModel::columnCount(const QModelIndex& /* parent */) const | ||
446 | { | ||
447 | return ColumnCountOffset + m_value.size(); | ||
448 | } | ||
449 | |||
450 | QVariant RegFieldTableModel::data(const QModelIndex& index, int role) const | ||
451 | { | ||
452 | int section = index.column(); | ||
453 | const soc_reg_field_t& field = m_reg.field[index.row()]; | ||
454 | /* column independent code */ | ||
455 | const RegThemeGroup *theme = 0; | ||
456 | switch(m_status[index.row()]) | ||
457 | { | ||
458 | case Normal: theme = &m_theme.normal; break; | ||
459 | case Diff: theme = &m_theme.diff; break; | ||
460 | case Error: theme = &m_theme.error; break; | ||
461 | case None: default: break; | ||
462 | } | ||
463 | if(role == Qt::FontRole) | ||
464 | return theme ? QVariant(theme->font) : QVariant(); | ||
465 | if(role == Qt::BackgroundRole) | ||
466 | return theme ? QVariant(theme->background) : QVariant(); | ||
467 | if(role == Qt::ForegroundRole) | ||
468 | return theme ? QVariant(theme->foreground) : QVariant(); | ||
469 | /* column dependent code */ | ||
470 | if(section == BitRangeColumn) | ||
471 | { | ||
472 | if(role == Qt::DisplayRole) | ||
473 | { | ||
474 | if(field.first_bit == field.last_bit) | ||
475 | return QVariant(QString("%1").arg(field.first_bit)); | ||
476 | else | ||
477 | return QVariant(QString("%1:%2").arg(field.last_bit).arg(field.first_bit)); | ||
478 | } | ||
479 | else if(role == Qt::TextAlignmentRole) | ||
480 | return QVariant(Qt::AlignVCenter | Qt::AlignHCenter); | ||
481 | else | ||
482 | return QVariant(); | ||
483 | } | ||
484 | if(section == NameColumn) | ||
485 | { | ||
486 | if(role == Qt::DisplayRole) | ||
487 | return QVariant(QString::fromStdString(field.name)); | ||
488 | else | ||
489 | return QVariant(); | ||
490 | } | ||
491 | if(section < FirstValueColumn + m_value.size()) | ||
492 | { | ||
493 | int idx = section - FirstValueColumn; | ||
494 | if(role == Qt::DisplayRole) | ||
495 | { | ||
496 | if(!m_value[idx].isValid()) | ||
497 | return QVariant("<error>"); | ||
498 | return QVariant::fromValue(SocFieldCachedValue(field, | ||
499 | field.extract(m_value[idx].value< soc_word_t >()))); | ||
500 | } | ||
501 | else if(role == Qt::EditRole) | ||
502 | { | ||
503 | if(!m_value[idx].isValid()) | ||
504 | return QVariant(); | ||
505 | return QVariant::fromValue(SocFieldCachedValue(field, | ||
506 | field.extract(m_value[idx].value< soc_word_t >()))); | ||
507 | } | ||
508 | else if(role == Qt::TextAlignmentRole) | ||
509 | return QVariant(Qt::AlignVCenter | Qt::AlignHCenter); | ||
510 | else | ||
511 | return QVariant(); | ||
512 | } | ||
513 | section -= m_value.size(); | ||
514 | if(section == DescColumnOffset) | ||
515 | { | ||
516 | if(role == Qt::DisplayRole) | ||
517 | return QVariant(QString::fromStdString(field.desc)); | ||
518 | else | ||
519 | return QVariant(); | ||
520 | } | ||
521 | return QVariant(); | ||
522 | } | ||
523 | |||
524 | bool RegFieldTableModel::setData(const QModelIndex& idx, const QVariant& value, int role) | ||
525 | { | ||
526 | if(role != Qt::EditRole) | ||
527 | return false; | ||
528 | int section = idx.column(); | ||
529 | if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size()) | ||
530 | return false; | ||
531 | section -= FirstValueColumn; | ||
532 | const SocFieldCachedValue& v = value.value< SocFieldCachedValue >(); | ||
533 | if(!m_value[section].isValid()) | ||
534 | return false; | ||
535 | soc_word_t old_val = m_value[section].value< soc_word_t >(); | ||
536 | m_value[section] = QVariant(v.field().replace(old_val, v.value())); | ||
537 | // update column | ||
538 | RecomputeTheme(); | ||
539 | emit dataChanged(index(0, section), index(rowCount() - 1, section)); | ||
540 | emit OnValueModified(section); | ||
541 | return true; | ||
542 | } | ||
543 | |||
544 | Qt::ItemFlags RegFieldTableModel::flags(const QModelIndex& index) const | ||
545 | { | ||
546 | Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; | ||
547 | int section = index.column(); | ||
548 | if(section < FirstValueColumn || section >= FirstValueColumn + m_value.size()) | ||
549 | return flags; | ||
550 | section -= FirstValueColumn; | ||
551 | if(m_value[section].isValid() && !m_read_only) | ||
552 | flags |= Qt::ItemIsEditable; | ||
553 | return flags; | ||
554 | } | ||
555 | |||
556 | QVariant RegFieldTableModel::headerData(int section, Qt::Orientation orientation, | ||
557 | int role) const | ||
558 | { | ||
559 | if(orientation == Qt::Vertical) | ||
560 | return QVariant(); | ||
561 | if(role != Qt::DisplayRole) | ||
562 | return QVariant(); | ||
563 | if(section == BitRangeColumn) | ||
564 | return QVariant("Bits"); | ||
565 | if(section == NameColumn) | ||
566 | return QVariant("Name"); | ||
567 | if(section < FirstValueColumn + m_value.size()) | ||
568 | { | ||
569 | int idx = section - FirstValueColumn; | ||
570 | if(m_value.size() == 1) | ||
571 | return QVariant("Value"); | ||
572 | else | ||
573 | return QVariant(QString("Value %1").arg((QChar)('A' + idx))); | ||
574 | } | ||
575 | section -= m_value.size(); | ||
576 | if(section == DescColumnOffset) | ||
577 | return QVariant("Description"); | ||
578 | return QVariant(); | ||
579 | } | ||
580 | |||
581 | void RegFieldTableModel::SetReadOnly(bool en) | ||
582 | { | ||
583 | if(en == m_read_only) | ||
584 | return; | ||
585 | m_read_only = en; | ||
586 | } | ||
587 | |||
588 | void RegFieldTableModel::SetRegister(const soc_reg_t& reg) | ||
589 | { | ||
590 | /* remove all rows */ | ||
591 | beginRemoveRows(QModelIndex(), 0, rowCount() - 1); | ||
592 | m_reg.field.clear(); | ||
593 | endRemoveRows(); | ||
594 | /* add them all */ | ||
595 | beginInsertRows(QModelIndex(), 0, reg.field.size() - 1); | ||
596 | m_reg = reg; | ||
597 | RecomputeTheme(); | ||
598 | endInsertRows(); | ||
599 | } | ||
600 | |||
601 | void RegFieldTableModel::SetValues(const QVector< QVariant >& values) | ||
602 | { | ||
603 | /* remove all value columns */ | ||
604 | beginRemoveColumns(QModelIndex(), FirstValueColumn, | ||
605 | FirstValueColumn + m_value.size() - 1); | ||
606 | m_value.clear(); | ||
607 | endRemoveColumns(); | ||
608 | /* add them back */ | ||
609 | beginInsertColumns(QModelIndex(), FirstValueColumn, | ||
610 | FirstValueColumn + values.size() - 1); | ||
611 | m_value = values; | ||
612 | RecomputeTheme(); | ||
613 | endInsertColumns(); | ||
614 | } | ||
615 | |||
616 | QVariant RegFieldTableModel::GetValue(int index) | ||
617 | { | ||
618 | return m_value[index]; | ||
619 | } | ||
620 | |||
621 | void RegFieldTableModel::SetTheme(const RegTheme& theme) | ||
622 | { | ||
623 | m_theme = theme; | ||
624 | RecomputeTheme(); | ||
625 | emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); | ||
626 | } | ||
627 | |||
628 | void RegFieldTableModel::RecomputeTheme() | ||
629 | { | ||
630 | m_status.resize(m_reg.field.size()); | ||
631 | for(size_t i = 0; i < m_reg.field.size(); i++) | ||
632 | { | ||
633 | m_status[i] = None; | ||
634 | if(!m_theme.valid || m_value.size() == 0) | ||
635 | continue; | ||
636 | m_status[i] = Normal; | ||
637 | const soc_reg_field_t& field = m_reg.field[i]; | ||
638 | QVariant val; | ||
639 | for(int j = 0; j < m_value.size(); j++) | ||
640 | { | ||
641 | QVariant val2 = m_value[j]; | ||
642 | if(!val2.isValid()) | ||
643 | continue; | ||
644 | val2 = QVariant(field.extract(val2.value< soc_word_t >())); | ||
645 | if(!val.isValid()) | ||
646 | val = val2; | ||
647 | else if(val != val2) | ||
648 | m_status[i] = Diff; | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | |||
653 | /** | ||
431 | * RegSexyDisplay | 654 | * RegSexyDisplay |
432 | */ | 655 | */ |
433 | RegSexyDisplay::RegSexyDisplay(const SocRegRef& reg, QWidget *parent) | 656 | RegSexyDisplay::RegSexyDisplay(const SocRegRef& reg, QWidget *parent) |
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: | |||
201 | protected: | 201 | protected: |
202 | }; | 202 | }; |
203 | 203 | ||
204 | struct RegThemeGroup | ||
205 | { | ||
206 | QBrush foreground; | ||
207 | QBrush background; | ||
208 | QFont font; | ||
209 | }; | ||
210 | |||
211 | struct RegTheme | ||
212 | { | ||
213 | RegTheme():valid(false) {} | ||
214 | bool valid; | ||
215 | RegThemeGroup normal; | ||
216 | RegThemeGroup diff; | ||
217 | RegThemeGroup error; | ||
218 | }; | ||
219 | |||
220 | class RegFieldTableModel : public QAbstractTableModel | ||
221 | { | ||
222 | Q_OBJECT | ||
223 | public: | ||
224 | RegFieldTableModel(QObject *parent); | ||
225 | virtual int rowCount(const QModelIndex & parent = QModelIndex()) const; | ||
226 | virtual int columnCount(const QModelIndex & parent = QModelIndex()) const; | ||
227 | virtual QVariant data(const QModelIndex & index, int role) const; | ||
228 | virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; | ||
229 | virtual Qt::ItemFlags flags (const QModelIndex & index) const; | ||
230 | virtual bool setData(const QModelIndex& index, const QVariant& value, int role); | ||
231 | |||
232 | void SetRegister(const soc_reg_t& reg); | ||
233 | /* values can either be an invalid QVariant() (means no value/error), or a | ||
234 | * QVariant containing a soc_word_t */ | ||
235 | void SetValues(const QVector< QVariant >& values); | ||
236 | QVariant GetValue(int index); | ||
237 | void SetTheme(const RegTheme& theme); | ||
238 | void SetReadOnly(bool en); | ||
239 | |||
240 | signals: | ||
241 | void OnValueModified(int index); | ||
242 | |||
243 | protected: | ||
244 | void RecomputeTheme(); | ||
245 | |||
246 | enum | ||
247 | { | ||
248 | BitRangeColumn = 0, | ||
249 | NameColumn, | ||
250 | FirstValueColumn, | ||
251 | DescColumnOffset = FirstValueColumn, /* offset from nr_values */ | ||
252 | ColumnCountOffset, /* offset from nr_values */ | ||
253 | }; | ||
254 | |||
255 | enum ColorStatus | ||
256 | { | ||
257 | None, | ||
258 | Normal, | ||
259 | Diff, | ||
260 | Error | ||
261 | }; | ||
262 | |||
263 | soc_reg_t m_reg; | ||
264 | QVector< QVariant > m_value; | ||
265 | QVector< ColorStatus > m_status; | ||
266 | RegTheme m_theme; | ||
267 | bool m_read_only; | ||
268 | }; | ||
269 | |||
204 | class RegSexyDisplay : public QWidget | 270 | class RegSexyDisplay : public QWidget |
205 | { | 271 | { |
206 | Q_OBJECT | 272 | Q_OBJECT |