clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name dissector_tables_model.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-18/lib/clang/18 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/build/ui/qt -isystem /builds/wireshark/wireshark/ui/qt -isystem /usr/include/x86_64-linux-gnu/qt6/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt6 -isystem /usr/include/x86_64-linux-gnu/qt6/QtCore -isystem /usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++ -isystem /usr/include/x86_64-linux-gnu/qt6/QtGui -isystem /usr/include/x86_64-linux-gnu/qt6/QtCore5Compat -isystem /usr/include/x86_64-linux-gnu/qt6/QtConcurrent -isystem /usr/include/x86_64-linux-gnu/qt6/QtPrintSupport -isystem /usr/include/x86_64-linux-gnu/qt6/QtMultimedia -isystem /usr/include/x86_64-linux-gnu/qt6/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt6/QtDBus -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D QT_CONCURRENT_LIB -D QT_CORE5COMPAT_LIB -D QT_CORE_LIB -D QT_DBUS_LIB -D QT_GUI_LIB -D QT_MULTIMEDIA_LIB -D QT_NETWORK_LIB -D QT_PRINTSUPPORT_LIB -D QT_WIDGETS_LIB -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build/ui/qt/qtui_autogen/include -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-truncation -Wno-format-nonliteral -std=c++17 -fdeprecated-macro -ferror-limit 19 -fwrapv -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fcolor-diagnostics -analyzer-output=html -dwarf-debug-flags /usr/lib/llvm-18/bin/clang --driver-mode=g++ -### --analyze -x c++ -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D QT_CONCURRENT_LIB -D QT_CORE5COMPAT_LIB -D QT_CORE_LIB -D QT_DBUS_LIB -D QT_GUI_LIB -D QT_MULTIMEDIA_LIB -D QT_NETWORK_LIB -D QT_PRINTSUPPORT_LIB -D QT_WIDGETS_LIB -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build/ui/qt/qtui_autogen/include -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/build/ui/qt -isystem /builds/wireshark/wireshark/ui/qt -isystem /usr/include/x86_64-linux-gnu/qt6/QtWidgets -isystem /usr/include/x86_64-linux-gnu/qt6 -isystem /usr/include/x86_64-linux-gnu/qt6/QtCore -isystem /usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++ -isystem /usr/include/x86_64-linux-gnu/qt6/QtGui -isystem /usr/include/x86_64-linux-gnu/qt6/QtCore5Compat -isystem /usr/include/x86_64-linux-gnu/qt6/QtConcurrent -isystem /usr/include/x86_64-linux-gnu/qt6/QtPrintSupport -isystem /usr/include/x86_64-linux-gnu/qt6/QtMultimedia -isystem /usr/include/x86_64-linux-gnu/qt6/QtNetwork -isystem /usr/include/x86_64-linux-gnu/qt6/QtDBus -fexcess-precision=fast -fstrict-flex-arrays=3 -fstack-clash-protection -fcf-protection=full -D _GLIBCXX_ASSERTIONS -fstack-protector-strong -fno-delete-null-pointer-checks -fno-strict-overflow -fno-strict-aliasing -fexceptions -Wno-format-truncation -Wno-format-nonliteral -fdiagnostics-color=always -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -std=c++17 -fPIC -fPIC /builds/wireshark/wireshark/ui/qt/models/dissector_tables_model.cpp -o /builds/wireshark/wireshark/sbout/2024-11-20-100252-3912-1 -Xclang -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2024-11-20-100252-3912-1 -x c++ /builds/wireshark/wireshark/ui/qt/models/dissector_tables_model.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | #include <ui/qt/models/dissector_tables_model.h> |
11 | #include <epan/ftypes/ftypes.h> |
12 | #include <epan/packet.h> |
13 | |
14 | #include <ui/qt/utils/variant_pointer.h> |
15 | #include "main_application.h" |
16 | |
17 | static const char* CUSTOM_TABLE_NAME = "Custom Tables"; |
18 | static const char* INTEGER_TABLE_NAME = "Integer Tables"; |
19 | static const char* STRING_TABLE_NAME = "String Tables"; |
20 | static const char* HEURISTIC_TABLE_NAME = "Heuristic Tables"; |
21 | |
22 | class IntegerTablesItem : public DissectorTablesItem |
23 | { |
24 | public: |
25 | IntegerTablesItem(unsigned int value, QString dissectorDescription, DissectorTablesItem* parent); |
26 | virtual ~IntegerTablesItem(); |
27 | |
28 | virtual bool lessThan(DissectorTablesItem &right) const; |
29 | |
30 | protected: |
31 | unsigned int value_; |
32 | }; |
33 | |
34 | |
35 | DissectorTablesItem::DissectorTablesItem(QString tableName, QString dissectorDescription, DissectorTablesItem* parent) : |
36 | ModelHelperTreeItem<DissectorTablesItem>(parent), |
37 | tableName_(tableName), |
38 | dissectorDescription_(dissectorDescription) |
39 | { |
40 | } |
41 | |
42 | DissectorTablesItem::~DissectorTablesItem() |
43 | { |
44 | } |
45 | |
46 | bool DissectorTablesItem::lessThan(DissectorTablesItem &right) const |
47 | { |
48 | if (tableName().compare(right.tableName(), Qt::CaseInsensitive) < 0) |
49 | return true; |
50 | |
51 | return false; |
52 | } |
53 | |
54 | |
55 | IntegerTablesItem::IntegerTablesItem(unsigned int value, QString dissectorDescription, DissectorTablesItem* parent) |
56 | : DissectorTablesItem(QStringLiteral("%1").arg(value), dissectorDescription, parent) |
57 | , value_(value) |
58 | { |
59 | } |
60 | |
61 | IntegerTablesItem::~IntegerTablesItem() |
62 | { |
63 | } |
64 | |
65 | bool IntegerTablesItem::lessThan(DissectorTablesItem &right) const |
66 | { |
67 | if (value_ == ((IntegerTablesItem&)right).value_) { |
68 | return DissectorTablesItem::lessThan(right); |
69 | } |
70 | |
71 | if (value_ < ((IntegerTablesItem&)right).value_) { |
72 | return true; |
73 | } |
74 | |
75 | return false; |
76 | } |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | DissectorTablesModel::DissectorTablesModel(QObject *parent) : |
86 | QAbstractItemModel(parent), |
87 | root_(new DissectorTablesItem(QStringLiteral("ROOT"), QStringLiteral("ROOT"), NULL)) |
88 | { |
89 | populate(); |
90 | } |
91 | |
92 | DissectorTablesModel::~DissectorTablesModel() |
93 | { |
94 | delete root_; |
95 | } |
96 | |
97 | int DissectorTablesModel::rowCount(const QModelIndex &parent) const |
98 | { |
99 | DissectorTablesItem *parent_item; |
100 | if (parent.column() > 0) |
101 | return 0; |
102 | |
103 | if (!parent.isValid()) |
104 | parent_item = root_; |
105 | else |
106 | parent_item = static_cast<DissectorTablesItem*>(parent.internalPointer()); |
107 | |
108 | if (parent_item == NULL) |
109 | return 0; |
110 | |
111 | return parent_item->childCount(); |
112 | } |
113 | |
114 | int DissectorTablesModel::columnCount(const QModelIndex&) const |
115 | { |
116 | return colLast; |
117 | } |
118 | |
119 | QModelIndex DissectorTablesModel::parent(const QModelIndex& index) const |
120 | { |
121 | if (!index.isValid()) |
122 | return QModelIndex(); |
123 | |
124 | DissectorTablesItem* item = static_cast<DissectorTablesItem*>(index.internalPointer()); |
125 | if (item != NULL) { |
126 | DissectorTablesItem* parent_item = item->parentItem(); |
127 | if (parent_item != NULL) { |
128 | if (parent_item == root_) |
129 | return QModelIndex(); |
130 | |
131 | return createIndex(parent_item->row(), 0, parent_item); |
132 | } |
133 | } |
134 | |
135 | return QModelIndex(); |
136 | } |
137 | |
138 | QModelIndex DissectorTablesModel::index(int row, int column, const QModelIndex& parent) const |
139 | { |
140 | if (!hasIndex(row, column, parent)) |
141 | return QModelIndex(); |
142 | |
143 | DissectorTablesItem *parent_item, *child_item; |
144 | |
145 | if (!parent.isValid()) |
146 | parent_item = root_; |
147 | else |
148 | parent_item = static_cast<DissectorTablesItem*>(parent.internalPointer()); |
149 | |
150 | Q_ASSERT(parent_item); |
151 | |
152 | child_item = parent_item->child(row); |
153 | if (child_item) { |
154 | return createIndex(row, column, child_item); |
155 | } |
156 | |
157 | return QModelIndex(); |
158 | } |
159 | |
160 | QVariant DissectorTablesModel::data(const QModelIndex &index, int role) const |
161 | { |
162 | if ((!index.isValid()) || (role != Qt::DisplayRole)) |
163 | return QVariant(); |
164 | |
165 | DissectorTablesItem* item = static_cast<DissectorTablesItem*>(index.internalPointer()); |
166 | if (item == NULL) |
167 | return QVariant(); |
168 | |
169 | switch ((enum DissectorTablesColumn)index.column()) |
170 | { |
171 | case colTableName: |
172 | return item->tableName(); |
173 | case colDissectorDescription: |
174 | return item->dissectorDescription(); |
175 | default: |
176 | break; |
177 | } |
178 | |
179 | return QVariant(); |
180 | } |
181 | |
182 | static void gatherProtocolDecodes(const char *, ftenum_t selector_type, void *key, void *value, void *item_ptr) |
183 | { |
184 | DissectorTablesItem* pdl_ptr = (DissectorTablesItem*)item_ptr; |
185 | if (pdl_ptr == NULL) |
186 | return; |
187 | |
188 | dtbl_entry_t *dtbl_entry = (dtbl_entry_t*)value; |
189 | dissector_handle_t handle = dtbl_entry_get_handle(dtbl_entry); |
190 | const QString dissector_description = dissector_handle_get_description(handle); |
191 | DissectorTablesItem *ti = NULL; |
192 | |
193 | switch (selector_type) { |
194 | case FT_UINT8: |
195 | case FT_UINT16: |
196 | case FT_UINT24: |
197 | case FT_UINT32: |
198 | ti = new IntegerTablesItem(GPOINTER_TO_UINT(key), dissector_description, pdl_ptr); |
199 | pdl_ptr->prependChild(ti); |
200 | break; |
201 | |
202 | case FT_STRING: |
203 | case FT_STRINGZ: |
204 | case FT_UINT_STRING: |
205 | case FT_STRINGZPAD: |
206 | case FT_STRINGZTRUNC: |
207 | ti = new DissectorTablesItem((const char *)key, dissector_description, pdl_ptr); |
208 | pdl_ptr->prependChild(ti); |
209 | break; |
210 | |
211 | case FT_BYTES: |
212 | ti = new DissectorTablesItem(dissector_handle_get_description(handle), dissector_description, pdl_ptr); |
213 | pdl_ptr->prependChild(ti); |
214 | break; |
215 | |
216 | default: |
217 | break; |
218 | } |
219 | } |
220 | |
221 | struct tables_root |
222 | { |
223 | DissectorTablesItem* custom_table; |
224 | DissectorTablesItem* integer_table; |
225 | DissectorTablesItem* string_table; |
226 | }; |
227 | |
228 | static void gatherTableNames(const char *short_name, const char *table_name, void *model_ptr) |
229 | { |
230 | struct tables_root* tables = (struct tables_root*)model_ptr; |
231 | if (model_ptr == NULL) |
232 | return; |
233 | |
234 | ftenum_t selector_type = get_dissector_table_selector_type(short_name); |
235 | DissectorTablesItem *dt_ti = NULL; |
236 | |
237 | switch (selector_type) { |
238 | case FT_UINT8: |
239 | case FT_UINT16: |
240 | case FT_UINT24: |
241 | case FT_UINT32: |
242 | dt_ti = new DissectorTablesItem(table_name, short_name, tables->integer_table); |
243 | tables->integer_table->prependChild(dt_ti); |
244 | break; |
245 | case FT_STRING: |
246 | case FT_STRINGZ: |
247 | case FT_UINT_STRING: |
248 | case FT_STRINGZPAD: |
249 | case FT_STRINGZTRUNC: |
250 | dt_ti = new DissectorTablesItem(table_name, short_name, tables->string_table); |
251 | tables->string_table->prependChild(dt_ti); |
252 | break; |
253 | case FT_BYTES: |
254 | dt_ti = new DissectorTablesItem(table_name, short_name, tables->custom_table); |
255 | tables->custom_table->prependChild(dt_ti); |
256 | break; |
257 | default: |
258 | |
259 | return; |
260 | } |
261 | |
262 | dissector_table_foreach(short_name, gatherProtocolDecodes, dt_ti); |
263 | } |
264 | |
265 | static void gatherHeurProtocolDecodes(const char *, struct heur_dtbl_entry *dtbl_entry, void *list_ptr) |
266 | { |
267 | DissectorTablesItem* hdl_ptr = (DissectorTablesItem*)list_ptr; |
268 | if (hdl_ptr == NULL) |
269 | return; |
270 | |
271 | if (dtbl_entry->protocol) { |
272 | QString longName = proto_get_protocol_long_name(dtbl_entry->protocol); |
273 | QString heurDisplayName = dtbl_entry->display_name; |
274 | if (! heurDisplayName.isEmpty()) |
275 | longName.append(QStringLiteral(" (%1)").arg(heurDisplayName)); |
276 | |
277 | DissectorTablesItem *heur = new DissectorTablesItem(longName, proto_get_protocol_short_name(dtbl_entry->protocol), hdl_ptr); |
278 | hdl_ptr->prependChild(heur); |
279 | } |
280 | } |
281 | |
282 | static void gatherHeurTableNames(const char *table_name, heur_dissector_list *list, void *heur_tables) |
283 | { |
284 | DissectorTablesItem* table = (DissectorTablesItem*)heur_tables; |
285 | if (table == NULL) |
| 1 | Assuming 'table' is not equal to NULL | |
|
| |
286 | return; |
287 | |
288 | QString desc_name = table_name; |
289 | if (list) { |
| |
| |
290 | const char *desc = heur_dissector_list_get_description(list); |
291 | if (desc) desc_name = desc; |
292 | } |
293 | DissectorTablesItem *heur = new DissectorTablesItem(desc_name, table_name, table); |
| |
294 | table->prependChild(heur); |
295 | |
296 | if (list) { |
| |
297 | heur_dissector_table_foreach(table_name, gatherHeurProtocolDecodes, heur); |
298 | } |
299 | } |
| 7 | | Potential leak of memory pointed to by 'heur' |
|
300 | |
301 | void DissectorTablesModel::populate() |
302 | { |
303 | beginResetModel(); |
304 | |
305 | struct tables_root tables; |
306 | |
307 | tables.custom_table = new DissectorTablesItem(tr(CUSTOM_TABLE_NAME), QString(""), root_); |
308 | root_->prependChild(tables.custom_table); |
309 | tables.integer_table = new DissectorTablesItem(tr(INTEGER_TABLE_NAME), QString(""), root_); |
310 | root_->prependChild(tables.integer_table); |
311 | tables.string_table = new DissectorTablesItem(tr(STRING_TABLE_NAME), QString(""), root_); |
312 | root_->prependChild(tables.string_table); |
313 | |
314 | dissector_all_tables_foreach_table(gatherTableNames, &tables, NULL); |
315 | |
316 | DissectorTablesItem* heuristic_table = new DissectorTablesItem(tr(HEURISTIC_TABLE_NAME), QString(""), root_); |
317 | root_->prependChild(heuristic_table); |
318 | |
319 | dissector_all_heur_tables_foreach_table(gatherHeurTableNames, heuristic_table, NULL); |
320 | |
321 | endResetModel(); |
322 | } |
323 | |
324 | |
325 | |
326 | |
327 | |
328 | DissectorTablesProxyModel::DissectorTablesProxyModel(QObject * parent) |
329 | : QSortFilterProxyModel(parent), |
330 | tableName_(tr("Table Type")), |
331 | dissectorDescription_(), |
332 | filter_() |
333 | { |
334 | } |
335 | |
336 | QVariant DissectorTablesProxyModel::headerData(int section, Qt::Orientation orientation, int role) const |
337 | { |
338 | if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { |
339 | |
340 | switch ((enum DissectorTablesModel::DissectorTablesColumn)section) { |
341 | case DissectorTablesModel::colTableName: |
342 | return tableName_; |
343 | case DissectorTablesModel::colDissectorDescription: |
344 | return dissectorDescription_; |
345 | default: |
346 | break; |
347 | } |
348 | } |
349 | return QVariant(); |
350 | } |
351 | |
352 | bool DissectorTablesProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const |
353 | { |
354 | |
355 | DissectorTablesItem* left_item = static_cast<DissectorTablesItem*>(left.internalPointer()); |
356 | DissectorTablesItem* right_item = static_cast<DissectorTablesItem*>(right.internalPointer()); |
357 | |
358 | if ((left_item != NULL) && (right_item != NULL)) { |
359 | return left_item->lessThan(*right_item); |
360 | } |
361 | |
362 | return false; |
363 | } |
364 | |
365 | bool DissectorTablesProxyModel::filterAcceptItem(DissectorTablesItem& item) const |
366 | { |
367 | if (filter_.isEmpty()) |
368 | return true; |
369 | |
370 | if (item.tableName().contains(filter_, Qt::CaseInsensitive) || item.dissectorDescription().contains(filter_, Qt::CaseInsensitive)) |
371 | return true; |
372 | |
373 | DissectorTablesItem *child_item; |
374 | for (int child_row = 0; child_row < item.childCount(); child_row++) |
375 | { |
376 | child_item = item.child(child_row); |
377 | if ((child_item != NULL) && (filterAcceptItem(*child_item))) |
378 | return true; |
379 | } |
380 | |
381 | return false; |
382 | } |
383 | |
384 | bool DissectorTablesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const |
385 | { |
386 | QModelIndex nameIdx = sourceModel()->index(sourceRow, DissectorTablesModel::colTableName, sourceParent); |
387 | DissectorTablesItem* item = static_cast<DissectorTablesItem*>(nameIdx.internalPointer()); |
388 | if (item == NULL) |
389 | return false; |
390 | |
391 | if (filterAcceptItem(*item)) |
392 | return true; |
393 | |
394 | return false; |
395 | } |
396 | |
397 | void DissectorTablesProxyModel::setFilter(const QString& filter) |
398 | { |
399 | filter_ = filter; |
400 | invalidateFilter(); |
401 | } |
402 | |
403 | void DissectorTablesProxyModel::adjustHeader(const QModelIndex ¤tIndex) |
404 | { |
405 | tableName_ = tr("Table Type"); |
406 | dissectorDescription_ = QString(); |
407 | if (currentIndex.isValid() && currentIndex.parent().isValid()) { |
408 | QString table; |
409 | |
410 | if (currentIndex.parent().parent().isValid()) { |
411 | table = data(index(currentIndex.parent().parent().row(), DissectorTablesModel::colTableName), Qt::DisplayRole).toString(); |
412 | if ((table.compare(CUSTOM_TABLE_NAME) == 0) || |
413 | (table.compare(STRING_TABLE_NAME) == 0)) { |
414 | tableName_ = tr("String"); |
415 | dissectorDescription_ = tr("Dissector Description"); |
416 | } else if (table.compare(INTEGER_TABLE_NAME) == 0) { |
417 | tableName_ = tr("Integer"); |
418 | dissectorDescription_ = tr("Dissector Description"); |
419 | } else if (table.compare(HEURISTIC_TABLE_NAME) == 0) { |
420 | tableName_ = tr("Protocol"); |
421 | dissectorDescription_ = tr("Short Name"); |
422 | } |
423 | } else { |
424 | table = data(index(currentIndex.parent().row(), DissectorTablesModel::colTableName), Qt::DisplayRole).toString(); |
425 | if ((table.compare(CUSTOM_TABLE_NAME) == 0) || |
426 | (table.compare(INTEGER_TABLE_NAME) == 0) || |
427 | (table.compare(STRING_TABLE_NAME) == 0)) { |
428 | tableName_ = tr("Table Name"); |
429 | dissectorDescription_ = tr("Selector Name"); |
430 | } else if (table.compare(HEURISTIC_TABLE_NAME) == 0) { |
431 | tableName_ = tr("Protocol"); |
432 | dissectorDescription_ = tr("Short Name"); |
433 | } |
434 | } |
435 | } |
436 | |
437 | |
438 | emit headerDataChanged(Qt::Vertical, 0, 1); |
439 | } |