1 /*
2 This file is part of the Okteta Kasten module, made within the KDE community.
3
4 SPDX-FileCopyrightText: 2008 Friedrich W. H. Kossebau <kossebau@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9 #include "statistictablemodel.hpp"
10
11 // Okteta core
12 #include <Okteta/Character>
13 #include <Okteta/CharCodec>
14 #include <Okteta/ValueCodec>
15 // KF
16 #include <KLocalizedString>
17 #include <KColorScheme>
18 // Qt
19 #include <QApplication>
20
21 namespace Kasten {
22
23 static constexpr QChar StatisticsDefaultSubstituteChar = QLatin1Char('.');
24 static constexpr QChar StatisticsDefaultUndefinedChar = QChar(QChar::ReplacementCharacter);
25 static constexpr Okteta::ValueCoding DefaultValueCoding = Okteta::HexadecimalCoding;
26 static constexpr int StatisticsByteSetSize = 256;
27
StatisticTableModel(int * byteCount,QObject * parent)28 StatisticTableModel::StatisticTableModel(int* byteCount, QObject* parent)
29 : QAbstractTableModel(parent)
30 , mByteCount(byteCount)
31 , mValueCoding(DefaultValueCoding)
32 , mValueCodec(Okteta::ValueCodec::createCodec(DefaultValueCoding))
33 , mCharCodec(Okteta::CharCodec::createCodec(Okteta::LocalEncoding))
34 , mSubstituteChar(StatisticsDefaultSubstituteChar)
35 , mUndefinedChar(StatisticsDefaultUndefinedChar)
36 {
37 }
38
~StatisticTableModel()39 StatisticTableModel::~StatisticTableModel()
40 {
41 delete mValueCodec;
42 delete mCharCodec;
43 }
44
update(int size)45 void StatisticTableModel::update(int size)
46 {
47 mSize = size;
48 emit dataChanged(index(0, CountId), index(StatisticsByteSetSize - 1, PercentId));
49 emit sizeChanged(mSize);
50 }
51
setSubstituteChar(QChar substituteChar)52 void StatisticTableModel::setSubstituteChar(QChar substituteChar)
53 {
54 if (substituteChar.isNull()) {
55 substituteChar = StatisticsDefaultSubstituteChar;
56 }
57
58 if (mSubstituteChar == substituteChar) {
59 return;
60 }
61
62 mSubstituteChar = substituteChar;
63
64 emit dataChanged(index(0, CharacterId), index(StatisticsByteSetSize - 1, CharacterId));
65 }
66
setUndefinedChar(QChar undefinedChar)67 void StatisticTableModel::setUndefinedChar(QChar undefinedChar)
68 {
69 if (undefinedChar.isNull()) {
70 undefinedChar = StatisticsDefaultUndefinedChar;
71 }
72
73 if (mUndefinedChar == undefinedChar) {
74 return;
75 }
76
77 mUndefinedChar = undefinedChar;
78
79 emit dataChanged(index(0, CharacterId), index(StatisticsByteSetSize - 1, CharacterId));
80 }
81
setValueCoding(int valueCoding)82 void StatisticTableModel::setValueCoding(int valueCoding)
83 {
84 // no changes?
85 if (mValueCoding == valueCoding) {
86 return;
87 }
88
89 delete mValueCodec;
90
91 mValueCoding = (Okteta::ValueCoding)valueCoding;
92 mValueCodec = Okteta::ValueCodec::createCodec(mValueCoding);
93 // CodedByte.resize( ByteCodec->encodingWidth() );
94
95 emit dataChanged(index(0, ValueId), index(StatisticsByteSetSize - 1, ValueId));
96 emit headerChanged();
97 }
98
setCharCodec(const QString & codeName)99 void StatisticTableModel::setCharCodec(const QString& codeName)
100 {
101 if (codeName == mCharCodec->name()) {
102 return;
103 }
104
105 delete mCharCodec;
106 mCharCodec = Okteta::CharCodec::createCodec(codeName);
107
108 emit dataChanged(index(0, CharacterId), index(StatisticsByteSetSize - 1, CharacterId));
109 }
110
rowCount(const QModelIndex & parent) const111 int StatisticTableModel::rowCount(const QModelIndex& parent) const
112 {
113 return (!parent.isValid()) ? StatisticsByteSetSize : 0;
114 }
115
columnCount(const QModelIndex & parent) const116 int StatisticTableModel::columnCount(const QModelIndex& parent) const
117 {
118 return (!parent.isValid()) ? NoOfIds : 0;
119 }
120
data(const QModelIndex & index,int role) const121 QVariant StatisticTableModel::data(const QModelIndex& index, int role) const
122 {
123 QVariant result;
124 if (role == Qt::DisplayRole) {
125 const unsigned char byte = index.row();
126 const int column = index.column();
127 switch (column)
128 {
129 case CharacterId:
130 {
131 const Okteta::Character decodedChar = mCharCodec->decode(byte);
132 result =
133 decodedChar.isUndefined() ?
134 i18nc("@item:intable character is not defined", "undef.") :
135 !decodedChar.isPrint() ?
136 QString(mSubstituteChar) :
137 QString(static_cast<QChar>(decodedChar));
138 // TODO: show proper descriptions for all control values, incl. space and delete
139 // cmp. KCharSelect
140 break;
141 }
142 case ValueId:
143 {
144 QString value;
145 mValueCodec->encode(&value, 0, byte);
146 result = value;
147 break;
148 }
149 case CountId:
150 result = (mSize == -1) ?
151 QVariant(QStringLiteral("-")) :
152 QVariant(mByteCount[byte]);
153 break;
154 case PercentId:
155 result = (mSize > 0) ?
156 // TODO: before we printed only a string (which killed sorting) with QString::number( x, 'f', 6 )
157 // Qt now cuts trailing 0s, results in unaligned numbers, not so beautiful.
158 QVariant(100.0 * (double)mByteCount[byte] / mSize) :
159 QVariant(QStringLiteral("-"));
160 break;
161 default:
162 ;
163 }
164 } else if (role == Qt::TextAlignmentRole) {
165 result = Qt::AlignRight;
166 } else if (role == Qt::ForegroundRole) {
167 const int column = index.column();
168 bool isInactive = false;
169 switch (column)
170 {
171 case CharacterId:
172 {
173 const unsigned char byte = index.row();
174 const Okteta::Character decodedChar = mCharCodec->decode(byte);
175 isInactive = decodedChar.isUndefined() || !decodedChar.isPrint();
176 break;
177 }
178 case CountId:
179 isInactive = (mSize == -1);
180 break;
181 case PercentId:
182 isInactive = (mSize <= 0);
183 break;
184 default:
185 ;
186 }
187 if (isInactive) {
188 const QPalette& palette = QApplication::palette();
189 const KColorScheme colorScheme(palette.currentColorGroup(), KColorScheme::View);
190 result = colorScheme.foreground(KColorScheme::InactiveText);
191 }
192 }
193
194 return result;
195 }
196
headerData(int section,Qt::Orientation orientation,int role) const197 QVariant StatisticTableModel::headerData(int section, Qt::Orientation orientation, int role) const
198 {
199 QVariant result;
200
201 if (role == Qt::DisplayRole) {
202 const QString titel =
203 section == ValueId ? (
204 mValueCoding == Okteta::HexadecimalCoding ? i18nc("@title:column short for Hexadecimal", "Hex") :
205 mValueCoding == Okteta::DecimalCoding ? i18nc("@title:column short for Decimal", "Dec") :
206 mValueCoding == Okteta::OctalCoding ? i18nc("@title:column short for Octal", "Oct") :
207 mValueCoding == Okteta::BinaryCoding ? i18nc("@title:column short for Binary", "Bin") :
208 QString()) :
209 section == CharacterId ? i18nc("@title:column short for Character", "Char") :
210 section == CountId ? i18nc("@title:column count of characters", "Count") :
211 section == PercentId ? i18nc("@title:column Percent of byte in total", "Percent") :
212 QString();
213 result = titel;
214 } else if (role == Qt::ToolTipRole) {
215 const QString titel =
216 section == ValueId ? (
217 mValueCoding == Okteta::HexadecimalCoding ?
218 i18nc("@info:tooltip column contains the value in hexadecimal format", "Hexadecimal") :
219 mValueCoding == Okteta::DecimalCoding ?
220 i18nc("@info:tooltip column contains the value in decimal format", "Decimal") :
221 mValueCoding == Okteta::OctalCoding ?
222 i18nc("@info:tooltip column contains the value in octal format", "Octal") :
223 mValueCoding == Okteta::BinaryCoding ?
224 i18nc("@info:tooltip column contains the value in binary format", "Binary") :
225 // else
226 QString()) :
227 section == CharacterId ?
228 i18nc("@info:tooltip column contains the character with the value", "Character") :
229 // section == CountId ? i18nc("@info:tooltip count of characters", "Count") :
230 // section == PercentId ? i18nc("@info:tooltip Percent of byte in total", "Percent") :
231 QString();
232 result = titel;
233 } else {
234 result = QAbstractTableModel::headerData(section, orientation, role);
235 }
236
237 return result;
238 }
239
240 }
241