44#include " utils.h"
55
66#include < QtGui/QBrush>
7+ #include < algorithm>
8+ #include < cassert>
79
810Q_DECLARE_METATYPE (calc_var_t )
911
10- VarTableModel::VarData::VarData(const calc_var_t &var) : info(var), data(reinterpret_cast <char *>(var.data), var.size), checked(Qt::Unchecked) {
11- info.data = reinterpret_cast <uint8_t *>(data.data ());
12- updatePreview ();
12+ VarTableModel::VarData::VarData(const calc_var_t &var) : info(var), previewState(PreviewState::Outdated), checked(false ) {
13+ info.data = new uint8_t [var.size ];
14+ memcpy (info.data , var.data , var.size );
15+ }
16+
17+ VarTableModel::VarData::~VarData () {
18+ delete[] info.data ;
19+ }
20+
21+ VarTableModel::VarData::VarData (VarData &&other) noexcept {
22+ info.data = nullptr ;
23+ *this = std::move (other);
24+ }
25+
26+ VarTableModel::VarData &VarTableModel::VarData::operator =(VarData &&other) noexcept {
27+ uint8_t *data = info.data ;
28+ info = other.info ;
29+ other.info .data = data;
30+ preview = std::move (other.preview );
31+ previewState = other.previewState ;
32+ checked = other.checked ;
33+ return *this ;
34+ }
35+
36+ uint8_t VarTableModel::VarData::updateInfo (const calc_var_t &var) {
37+ uint8_t changed = 0 ;
38+ if (var.namelen != info.namelen ||
39+ 0 != memcmp (var.name , info.name , var.namelen )) {
40+ changed |= (1 << VAR_NAME_COL);
41+ }
42+ if (var.archived != info.archived ) {
43+ changed |= (1 << VAR_LOCATION_COL);
44+ }
45+ if (var.type != info.type ) {
46+ changed |= (1 << VAR_TYPE_COL);
47+ }
48+ uint8_t *data = info.data ;
49+ if (var.size != info.size ) {
50+ changed |= (1 << VAR_SIZE_COL) | (1 << VAR_PREVIEW_COL);
51+ data = new uint8_t [var.size ];
52+ delete[] info.data ;
53+ } else if (0 != memcmp (var.data , data, var.size )) {
54+ changed |= (1 << VAR_PREVIEW_COL);
55+ }
56+ info = var;
57+ info.data = data;
58+ if (changed & (1 << VAR_PREVIEW_COL)) {
59+ memcpy (info.data , var.data , var.size );
60+ previewState = PreviewState::Outdated;
61+ }
62+ return changed;
1363}
1464
1565void VarTableModel::VarData::updatePreview () {
16- previewValid = true ;
66+ previewState = PreviewState::Valid ;
1767 if (info.size <= 2 ) {
1868 preview = tr (" Empty" );
19- previewValid = false ;
69+ previewState = PreviewState::Invalid ;
2070 } else if (calc_var_is_asmprog (&info)) {
2171 preview = tr (" Can't preview this" );
22- previewValid = false ;
72+ previewState = PreviewState::Invalid ;
2373 } else if (calc_var_is_internal (&info) && info.name [0 ] != ' #' ) { // # is previewable
2474 preview = tr (" Can't preview this OS variable" );
25- previewValid = false ;
75+ previewState = PreviewState::Invalid ;
2676 } else {
2777 try {
2878 preview = QString::fromStdString (calc_var_content_string (info)).trimmed ().replace (" \n " , " \\ " );
@@ -32,7 +82,7 @@ void VarTableModel::VarData::updatePreview() {
3282 }
3383 } catch (...) {
3484 preview = tr (" Can't preview this" );
35- previewValid = false ;
85+ previewState = PreviewState::Invalid ;
3686 }
3787 }
3888}
@@ -48,37 +98,91 @@ void VarTableModel::clear() {
4898 endResetModel ();
4999}
50100
101+ static bool varLess (const calc_var_t &var, const calc_var_t &other) {
102+ return calc_var_compare_names (&var, &other) < 0 ;
103+ }
104+
51105void VarTableModel::refresh () {
52106 calc_var_t var;
53107
54- clear () ;
108+ std::vector< calc_var_t > newVars ;
55109
56110 vat_search_init (&var);
57111 while (vat_search_next (&var)) {
58112 if (var.named || var.size > 2 ) {
59- int row = vars.size ();
60- beginInsertRows (QModelIndex (), row, row);
61- vars.push_back (VarData (var));
113+ newVars.push_back (var);
114+ }
115+ }
116+
117+ std::sort (newVars.begin (), newVars.end (), varLess);
118+
119+ auto oldIter = vars.begin ();
120+ auto newIter = newVars.begin ();
121+ while (newIter != newVars.end ()) {
122+ size_t row = oldIter - vars.begin ();
123+ // Remove old vars smaller than the next new var
124+ auto oldRemoveEnd = std::find_if_not (oldIter, vars.end (), [=](const VarData &var) { return varLess (var.info , *newIter); });
125+ if (oldIter != oldRemoveEnd) {
126+ beginRemoveRows (QModelIndex (), row, row + (oldRemoveEnd - oldIter - 1 ));
127+ oldIter = vars.erase (oldIter, oldRemoveEnd);
128+ endRemoveRows ();
129+ }
130+ // Insert new vars smaller than the next old var, or insert all if no more old vars
131+ auto newInsertEnd = newVars.end ();
132+ if (oldIter != vars.end ()) {
133+ newInsertEnd = std::find_if_not (newIter, newVars.end (), [=](const calc_var_t &var) { return varLess (var, oldIter->info ); });
134+ }
135+ if (newIter != newInsertEnd) {
136+ beginInsertRows (QModelIndex (), row, row + (newInsertEnd - newIter - 1 ));
137+ oldIter = vars.insert (oldIter, newIter, newInsertEnd);
62138 endInsertRows ();
139+ oldIter += (newInsertEnd - newIter);
140+ newIter = newInsertEnd;
141+ } else {
142+ // No new vars were smaller, and the old var cannot be smaller because those were already removed, so they're equal
143+ assert (oldIter != vars.end ());
144+ // Update the old variable with the new variable data
145+ uint8_t changed = oldIter->updateInfo (*newIter);
146+ // Inform the view of changed columns
147+ for (uint8_t col = 0 ; col < VAR_NUM_COLS; col++) {
148+ if (changed & (1 << col)) {
149+ QModelIndex cell = index (row, col);
150+ emit dataChanged (cell, cell);
151+ }
152+ }
153+ oldIter++;
154+ newIter++;
63155 }
64156 }
157+ // Remove any remaining old vars
158+ if (oldIter != vars.end ()) {
159+ beginRemoveRows (QModelIndex (), oldIter - vars.begin (), vars.size () - 1 );
160+ vars.erase (oldIter, vars.end ());
161+ endRemoveRows ();
162+ }
65163}
66164
67165void VarTableModel::retranslate () {
68166 if (!vars.empty ()) {
69167 for (VarData &var : vars) {
70- var.updatePreview ();
168+ // Only invalid previews are translated
169+ if (var.previewState == PreviewState::Invalid) {
170+ var.previewState = PreviewState::Outdated;
171+ }
71172 }
72- emit dataChanged (index (0 , 0 ), index (rowCount () - 1 , columnCount () - 1 ));
173+ emit dataChanged (index (0 , VAR_LOCATION_COL ), index (vars. size () - 1 , VAR_NUM_COLS - 1 ));
73174 }
74- emit headerDataChanged (Qt::Horizontal, 0 , columnCount () - 1 );
175+ emit headerDataChanged (Qt::Horizontal, 0 , VAR_NUM_COLS - 1 );
75176}
76177
77178QVariant VarTableModel::data (const QModelIndex &index, int role) const {
78179 if (!index.isValid ()) {
79180 return QVariant ();
80181 }
81- const VarData &var = vars[index.row ()];
182+ VarData &var = vars[index.row ()];
183+ if (index.column () == VAR_PREVIEW_COL && var.previewState == PreviewState::Outdated) {
184+ var.updatePreview ();
185+ }
82186 switch (role) {
83187 case Qt::DisplayRole:
84188 switch (index.column ()) {
@@ -104,17 +208,17 @@ QVariant VarTableModel::data(const QModelIndex &index, int role) const {
104208 };
105209 case Qt::FontRole:
106210 if (index.column () == VAR_PREVIEW_COL) {
107- return var.previewValid ? varPreviewCEFont : varPreviewItalicFont ;
211+ return var.previewState == PreviewState::Invalid ? varPreviewItalicFont : varPreviewCEFont ;
108212 }
109213 return QVariant ();
110214 case Qt::ForegroundRole:
111- if (index.column () == VAR_PREVIEW_COL && ! var.previewValid ) {
215+ if (index.column () == VAR_PREVIEW_COL && var.previewState == PreviewState::Invalid ) {
112216 return QBrush (Qt::gray);
113217 }
114218 return QVariant ();
115219 case Qt::CheckStateRole:
116220 if (index.column () == VAR_NAME_COL) {
117- return var.checked ;
221+ return var.checked ? Qt::Checked : Qt::Unchecked ;
118222 }
119223 return QVariant ();
120224 case Qt::UserRole:
@@ -126,7 +230,7 @@ QVariant VarTableModel::data(const QModelIndex &index, int role) const {
126230
127231bool VarTableModel::setData (const QModelIndex &index, const QVariant &value, int role) {
128232 if (index.isValid () && index.column () == VAR_NAME_COL && role == Qt::CheckStateRole) {
129- vars[index.row ()].checked = qvariant_cast<Qt::CheckState>(value);
233+ vars[index.row ()].checked = qvariant_cast<Qt::CheckState>(value) == Qt::Checked ;
130234 emit dataChanged (index, index, { Qt::CheckStateRole });
131235 return true ;
132236 }
0 commit comments