File: | builds/wireshark/wireshark/ui/qt/models/coloring_rules_model.cpp |
Warning: | line 245, column 5 Potential leak of memory pointed to by 'dst_item' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* coloring_rules_model.cpp | |||
2 | * Data model for coloring rules. | |||
3 | * | |||
4 | * Wireshark - Network traffic analyzer | |||
5 | * By Gerald Combs <[email protected]> | |||
6 | * Copyright 1998 Gerald Combs | |||
7 | * | |||
8 | * SPDX-License-Identifier: GPL-2.0-or-later | |||
9 | */ | |||
10 | #include "config.h" | |||
11 | ||||
12 | #include "coloring_rules_model.h" | |||
13 | ||||
14 | #include <errno(*__errno_location ()).h> | |||
15 | ||||
16 | #include "ui/ws_ui_util.h" //for color_filter_add_cb | |||
17 | ||||
18 | #include <ui/qt/utils/color_utils.h> | |||
19 | #include <ui/qt/utils/qt_ui_utils.h> | |||
20 | #include <ui/qt/utils/variant_pointer.h> | |||
21 | #include <ui/qt/utils/wireshark_mime_data.h> | |||
22 | ||||
23 | #include <QMimeData> | |||
24 | #include <QJsonDocument> | |||
25 | #include <QJsonObject> | |||
26 | #include <QJsonArray> | |||
27 | ||||
28 | ColoringRuleItem::ColoringRuleItem(bool disabled, QString name, QString filter, QColor foreground, QColor background, ColoringRuleItem* parent) | |||
29 | : ModelHelperTreeItem<ColoringRuleItem>(parent), | |||
30 | disabled_(disabled), | |||
31 | name_(name), | |||
32 | filter_(filter), | |||
33 | foreground_(foreground), | |||
34 | background_(background) | |||
35 | { | |||
36 | } | |||
37 | ||||
38 | ColoringRuleItem::~ColoringRuleItem() | |||
39 | { | |||
40 | ||||
41 | } | |||
42 | ||||
43 | ColoringRuleItem::ColoringRuleItem(color_filter_t *colorf, ColoringRuleItem* parent) | |||
44 | : ModelHelperTreeItem<ColoringRuleItem>(parent), | |||
45 | disabled_(colorf->disabled), | |||
46 | name_(colorf->filter_name), | |||
47 | filter_(colorf->filter_text), | |||
48 | foreground_(ColorUtils::fromColorT(colorf->fg_color)), | |||
49 | background_(ColorUtils::fromColorT(colorf->bg_color)) | |||
50 | { | |||
51 | } | |||
52 | ||||
53 | ColoringRuleItem::ColoringRuleItem(const ColoringRuleItem& item) | |||
54 | : ModelHelperTreeItem<ColoringRuleItem>(item.parent_), | |||
55 | disabled_(item.disabled_), | |||
56 | name_(item.name_), | |||
57 | filter_(item.filter_), | |||
58 | foreground_(item.foreground_), | |||
59 | background_(item.background_) | |||
60 | { | |||
61 | } | |||
62 | ||||
63 | ColoringRuleItem& ColoringRuleItem::operator=(ColoringRuleItem& rhs) | |||
64 | { | |||
65 | disabled_ = rhs.disabled_; | |||
66 | name_ = rhs.name_; | |||
67 | filter_ = rhs.filter_; | |||
68 | foreground_ = rhs.foreground_; | |||
69 | background_ = rhs.background_; | |||
70 | return *this; | |||
71 | } | |||
72 | ||||
73 | // Callback for color_filters_clone. | |||
74 | void | |||
75 | color_filter_add_cb(color_filter_t *colorf, void *user_data) | |||
76 | { | |||
77 | ColoringRulesModel *model = (ColoringRulesModel*)user_data; | |||
78 | ||||
79 | if (model == NULL__null) | |||
80 | return; | |||
81 | ||||
82 | model->addColor(colorf); | |||
83 | } | |||
84 | ||||
85 | ColoringRulesModel::ColoringRulesModel(QColor defaultForeground, QColor defaultBackground, QObject *parent) : | |||
86 | QAbstractItemModel(parent), | |||
87 | root_(new ColoringRuleItem(false, "", "", QColor(), QColor(), NULL__null)), | |||
88 | conversation_colors_(NULL__null), | |||
89 | defaultForeground_(defaultForeground), | |||
90 | defaultBackground_(defaultBackground) | |||
91 | ||||
92 | { | |||
93 | color_filters_clone(this, color_filter_add_cb); | |||
94 | } | |||
95 | ||||
96 | ColoringRulesModel::~ColoringRulesModel() | |||
97 | { | |||
98 | delete root_; | |||
99 | color_filter_list_delete(&conversation_colors_); | |||
100 | } | |||
101 | ||||
102 | GSList *ColoringRulesModel::createColorFilterList() | |||
103 | { | |||
104 | GSList *cfl = NULL__null; | |||
105 | for (int row = 0; row < root_->childCount(); row++) | |||
106 | { | |||
107 | ColoringRuleItem* rule = root_->child(row); | |||
108 | if (rule == NULL__null) | |||
109 | continue; | |||
110 | ||||
111 | color_t fg = ColorUtils::toColorT(rule->foreground_); | |||
112 | color_t bg = ColorUtils::toColorT(rule->background_); | |||
113 | color_filter_t *colorf = color_filter_new(rule->name_.toUtf8().constData(), | |||
114 | rule->filter_.toUtf8().constData(), | |||
115 | &bg, &fg, rule->disabled_); | |||
116 | cfl = g_slist_append(cfl, colorf); | |||
117 | } | |||
118 | ||||
119 | return cfl; | |||
120 | } | |||
121 | ||||
122 | void ColoringRulesModel::addColor(color_filter_t* colorf) | |||
123 | { | |||
124 | if (!colorf) return; | |||
125 | ||||
126 | if (strstr(colorf->filter_name, CONVERSATION_COLOR_PREFIX"___conversation_color_filter___") != NULL__null) { | |||
127 | conversation_colors_ = g_slist_append(conversation_colors_, colorf); | |||
128 | } else { | |||
129 | int count = root_->childCount(); | |||
130 | ||||
131 | beginInsertRows(QModelIndex(), count, count); | |||
132 | ColoringRuleItem* item = new ColoringRuleItem(colorf, root_); | |||
133 | color_filter_delete(colorf); | |||
134 | root_->appendChild(item); | |||
135 | endInsertRows(); | |||
136 | } | |||
137 | } | |||
138 | ||||
139 | void ColoringRulesModel::addColor(bool disabled, QString filter, QColor foreground, QColor background) | |||
140 | { | |||
141 | //add rule to top of the list | |||
142 | beginInsertRows(QModelIndex(), 0, 0); | |||
143 | ColoringRuleItem* item = new ColoringRuleItem(disabled, tr("New coloring rule"), filter, foreground, background, root_); | |||
144 | root_->prependChild(item); | |||
145 | endInsertRows(); | |||
146 | } | |||
147 | ||||
148 | ||||
149 | bool ColoringRulesModel::importColors(QString filename, QString& err) | |||
150 | { | |||
151 | bool success = true; | |||
152 | char* err_msg = NULL__null; | |||
153 | if (!color_filters_import(filename.toUtf8().constData(), this, &err_msg, color_filter_add_cb)) { | |||
154 | err = gchar_free_to_qstring(err_msg); | |||
155 | success = false; | |||
156 | } | |||
157 | ||||
158 | return success; | |||
159 | } | |||
160 | ||||
161 | bool ColoringRulesModel::exportColors(QString filename, QString& err) | |||
162 | { | |||
163 | GSList *cfl = createColorFilterList(); | |||
164 | bool success = true; | |||
165 | char* err_msg = NULL__null; | |||
166 | if (!color_filters_export(filename.toUtf8().constData(), cfl, false, &err_msg)) { | |||
167 | err = gchar_free_to_qstring(err_msg); | |||
168 | success = false; | |||
169 | } | |||
170 | color_filter_list_delete(&cfl); | |||
171 | ||||
172 | return success; | |||
173 | } | |||
174 | ||||
175 | bool ColoringRulesModel::writeColors(QString& err) | |||
176 | { | |||
177 | GSList *cfl = createColorFilterList(); | |||
178 | bool success = true; | |||
179 | char* err_msg = NULL__null; | |||
180 | if (!color_filters_apply(conversation_colors_, cfl, &err_msg)) { | |||
181 | err = gchar_free_to_qstring(err_msg); | |||
182 | success = false; | |||
183 | } | |||
184 | if (!color_filters_write(cfl, &err_msg)) { | |||
185 | err = tr("Unable to save coloring rules: %1").arg(g_strerror(errno(*__errno_location ()))); | |||
186 | success = false; | |||
187 | g_free(err_msg); | |||
188 | } | |||
189 | color_filter_list_delete(&cfl); | |||
190 | ||||
191 | return success; | |||
192 | } | |||
193 | ||||
194 | bool ColoringRulesModel::insertRows(int row, int count, const QModelIndex& parent) | |||
195 | { | |||
196 | // sanity check insertion | |||
197 | if (row < 0) | |||
198 | return false; | |||
199 | ||||
200 | beginInsertRows(parent, row, row+(count-1)); | |||
201 | ||||
202 | for (int i = row; i < row + count; i++) | |||
203 | { | |||
204 | ColoringRuleItem* item = new ColoringRuleItem(true, tr("New coloring rule"), "", defaultForeground_, defaultBackground_, root_); | |||
205 | root_->insertChild(i, item); | |||
206 | /* Automatically enable the new coloring rule */ | |||
207 | setData(index(i, colName, parent), Qt::Checked, Qt::CheckStateRole); | |||
208 | } | |||
209 | ||||
210 | endInsertRows(); | |||
211 | return true; | |||
212 | } | |||
213 | ||||
214 | bool ColoringRulesModel::removeRows(int row, int count, const QModelIndex& parent) | |||
215 | { | |||
216 | if (row < 0) | |||
217 | return false; | |||
218 | ||||
219 | beginRemoveRows(parent, row, row+(count-1)); | |||
220 | for (int i = row; i < row + count; i++) | |||
221 | { | |||
222 | root_->removeChild(row); | |||
223 | } | |||
224 | endRemoveRows(); | |||
225 | ||||
226 | return true; | |||
227 | } | |||
228 | ||||
229 | bool ColoringRulesModel::copyRow(int dst_row, int src_row) | |||
230 | { | |||
231 | if (src_row < 0 || src_row >= rowCount() || dst_row < 0 || dst_row >= rowCount()) { | |||
| ||||
232 | return false; | |||
233 | } | |||
234 | ||||
235 | ColoringRuleItem* src_item = root_->child(src_row); | |||
236 | if (src_item == NULL__null) | |||
237 | return false; | |||
238 | ||||
239 | ColoringRuleItem* dst_item = new ColoringRuleItem(*src_item); | |||
240 | if (dst_item
| |||
241 | return false; | |||
242 | ||||
243 | beginInsertRows(QModelIndex(), dst_row, dst_row); | |||
244 | root_->insertChild(dst_row, dst_item); | |||
245 | endInsertRows(); | |||
| ||||
246 | ||||
247 | return true; | |||
248 | } | |||
249 | ||||
250 | Qt::ItemFlags ColoringRulesModel::flags(const QModelIndex &index) const | |||
251 | { | |||
252 | Qt::ItemFlags flags = QAbstractItemModel::flags(index); | |||
253 | switch (index.column()) | |||
254 | { | |||
255 | case colName: | |||
256 | flags |= (Qt::ItemIsUserCheckable|Qt::ItemIsEditable); | |||
257 | break; | |||
258 | case colFilter: | |||
259 | flags |= Qt::ItemIsEditable; | |||
260 | break; | |||
261 | } | |||
262 | ||||
263 | if (index.isValid()) | |||
264 | flags |= (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); | |||
265 | else | |||
266 | flags |= Qt::ItemIsDropEnabled; | |||
267 | ||||
268 | return flags; | |||
269 | } | |||
270 | ||||
271 | ||||
272 | QVariant ColoringRulesModel::data(const QModelIndex &index, int role) const | |||
273 | { | |||
274 | if (!index.isValid()) | |||
275 | return QVariant(); | |||
276 | ||||
277 | ColoringRuleItem* rule = root_->child(index.row()); | |||
278 | if (rule == NULL__null) | |||
279 | return QVariant(); | |||
280 | ||||
281 | switch (role) | |||
282 | { | |||
283 | case Qt::DisplayRole: | |||
284 | case Qt::EditRole: | |||
285 | switch(index.column()) | |||
286 | { | |||
287 | case colName: | |||
288 | return rule->name_; | |||
289 | case colFilter: | |||
290 | return rule->filter_; | |||
291 | } | |||
292 | break; | |||
293 | case Qt::CheckStateRole: | |||
294 | switch(index.column()) | |||
295 | { | |||
296 | case colName: | |||
297 | return rule->disabled_ ? Qt::Unchecked : Qt::Checked; | |||
298 | } | |||
299 | break; | |||
300 | case Qt::BackgroundRole: | |||
301 | return rule->background_; | |||
302 | case Qt::ForegroundRole: | |||
303 | return rule->foreground_; | |||
304 | } | |||
305 | return QVariant(); | |||
306 | } | |||
307 | ||||
308 | bool ColoringRulesModel::setData(const QModelIndex &dataIndex, const QVariant &value, int role) | |||
309 | { | |||
310 | if (!dataIndex.isValid()) | |||
311 | return false; | |||
312 | ||||
313 | if (data(dataIndex, role) == value) { | |||
314 | // Data appears unchanged, do not do additional checks. | |||
315 | return true; | |||
316 | } | |||
317 | ||||
318 | ColoringRuleItem* rule = root_->child(dataIndex.row()); | |||
319 | if (rule == NULL__null) | |||
320 | return false; | |||
321 | ||||
322 | QModelIndex topLeft = dataIndex, | |||
323 | bottomRight = dataIndex; | |||
324 | ||||
325 | switch (role) | |||
326 | { | |||
327 | case Qt::EditRole: | |||
328 | switch (dataIndex.column()) | |||
329 | { | |||
330 | case colName: | |||
331 | rule->name_ = value.toString(); | |||
332 | break; | |||
333 | case colFilter: | |||
334 | rule->filter_ = value.toString(); | |||
335 | break; | |||
336 | default: | |||
337 | return false; | |||
338 | } | |||
339 | break; | |||
340 | case Qt::CheckStateRole: | |||
341 | switch (dataIndex.column()) | |||
342 | { | |||
343 | case colName: | |||
344 | rule->disabled_ = (value.toInt() == Qt::Checked) ? false : true; | |||
345 | break; | |||
346 | default: | |||
347 | return false; | |||
348 | } | |||
349 | break; | |||
350 | case Qt::BackgroundRole: | |||
351 | #if (QT_VERSION((6<<16)|(4<<8)|(2)) >= QT_VERSION_CHECK(6, 0, 0)((6<<16)|(0<<8)|(0))) | |||
352 | if (!value.canConvert<QColor>()) | |||
353 | #else | |||
354 | if (!value.canConvert(QVariant::Color)) | |||
355 | #endif | |||
356 | return false; | |||
357 | ||||
358 | rule->background_ = QColor(value.toString()); | |||
359 | break; | |||
360 | case Qt::ForegroundRole: | |||
361 | #if (QT_VERSION((6<<16)|(4<<8)|(2)) >= QT_VERSION_CHECK(6, 0, 0)((6<<16)|(0<<8)|(0))) | |||
362 | if (!value.canConvert<QColor>()) | |||
363 | #else | |||
364 | if (!value.canConvert(QVariant::Color)) | |||
365 | #endif | |||
366 | return false; | |||
367 | ||||
368 | rule->foreground_ = QColor(value.toString()); | |||
369 | break; | |||
370 | case Qt::UserRole: | |||
371 | { | |||
372 | ColoringRuleItem* new_rule = VariantPointer<ColoringRuleItem>::asPtr(value); | |||
373 | *rule = *new_rule; | |||
374 | topLeft = index(dataIndex.row(), colName); | |||
375 | bottomRight = index(dataIndex.row(), colFilter); | |||
376 | break; | |||
377 | } | |||
378 | default: | |||
379 | return false; | |||
380 | } | |||
381 | ||||
382 | QVector<int> roles; | |||
383 | roles << role; | |||
384 | ||||
385 | emit dataChanged(topLeft, bottomRight, roles); | |||
386 | ||||
387 | return true; | |||
388 | ||||
389 | } | |||
390 | ||||
391 | QVariant ColoringRulesModel::headerData(int section, Qt::Orientation orientation, int role) const | |||
392 | { | |||
393 | if (role != Qt::DisplayRole || orientation != Qt::Horizontal) | |||
394 | return QVariant(); | |||
395 | ||||
396 | switch ((ColoringRulesColumn)section) { | |||
397 | case colName: | |||
398 | return tr("Name"); | |||
399 | case colFilter: | |||
400 | return tr("Filter"); | |||
401 | default: | |||
402 | break; | |||
403 | } | |||
404 | ||||
405 | return QVariant(); | |||
406 | } | |||
407 | ||||
408 | Qt::DropActions ColoringRulesModel::supportedDropActions() const | |||
409 | { | |||
410 | return Qt::MoveAction | Qt::CopyAction; | |||
411 | } | |||
412 | ||||
413 | QStringList ColoringRulesModel::mimeTypes() const | |||
414 | { | |||
415 | return QStringList() << WiresharkMimeData::ColoringRulesMimeType; | |||
416 | } | |||
417 | ||||
418 | QMimeData* ColoringRulesModel::mimeData(const QModelIndexList &indexes) const | |||
419 | { | |||
420 | //if the list is empty, don't return an empty list | |||
421 | if (indexes.count() == 0) | |||
422 | return NULL__null; | |||
423 | ||||
424 | QMimeData *mimeData = new QMimeData(); | |||
425 | ||||
426 | QJsonArray data; | |||
427 | foreach (const QModelIndex & index, indexes)for (auto _container_427 = QtPrivate::qMakeForeachContainer(indexes ); _container_427.i != _container_427.e; ++_container_427.i) if (const QModelIndex & index = *_container_427.i; false) { } else | |||
428 | { | |||
429 | if (index.column() == 0) | |||
430 | { | |||
431 | ColoringRuleItem * item = root_->child(index.row()); | |||
432 | QJsonObject entry; | |||
433 | entry["disabled"] = item->disabled_; | |||
434 | entry["name"] = item->name_; | |||
435 | entry["filter"] = item->filter_; | |||
436 | entry["foreground"] = QVariant::fromValue(item->foreground_).toString(); | |||
437 | entry["background"] = QVariant::fromValue(item->background_).toString(); | |||
438 | data.append(entry); | |||
439 | } | |||
440 | } | |||
441 | ||||
442 | QJsonObject dataSet; | |||
443 | dataSet["coloringrules"] = data; | |||
444 | QByteArray encodedData = QJsonDocument(dataSet).toJson(); | |||
445 | ||||
446 | mimeData->setData(WiresharkMimeData::ColoringRulesMimeType, encodedData); | |||
447 | return mimeData; | |||
448 | } | |||
449 | ||||
450 | bool ColoringRulesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) | |||
451 | { | |||
452 | //clear any previous dragDrop information | |||
453 | dragDropRows_.clear(); | |||
454 | ||||
455 | if (action == Qt::IgnoreAction) | |||
456 | return true; | |||
457 | ||||
458 | if (!data->hasFormat(WiresharkMimeData::ColoringRulesMimeType) || column > 0) | |||
459 | return false; | |||
460 | ||||
461 | int beginRow; | |||
462 | ||||
463 | if (row != -1) | |||
464 | beginRow = row; | |||
465 | else if (parent.isValid()) | |||
466 | beginRow = parent.row(); | |||
467 | else | |||
468 | beginRow = rowCount(); | |||
469 | ||||
470 | QList<QVariant> rules; | |||
471 | ||||
472 | QJsonDocument encodedData = QJsonDocument::fromJson(data->data(WiresharkMimeData::ColoringRulesMimeType)); | |||
473 | if (! encodedData.isObject() || ! encodedData.object().contains("coloringrules")) | |||
474 | return false; | |||
475 | ||||
476 | QJsonArray dataArray = encodedData.object()["coloringrules"].toArray(); | |||
477 | ||||
478 | for (int datarow = 0; datarow < dataArray.count(); datarow++) | |||
479 | { | |||
480 | QJsonObject entry = dataArray.at(datarow).toObject(); | |||
481 | ||||
482 | if (! entry.contains("foreground") || ! entry.contains("background") || ! entry.contains("filter")) | |||
483 | continue; | |||
484 | ||||
485 | QColor fgColor = entry["foreground"].toVariant().value<QColor>(); | |||
486 | QColor bgColor = entry["background"].toVariant().value<QColor>(); | |||
487 | ||||
488 | ColoringRuleItem * item = new ColoringRuleItem( | |||
489 | entry["disabled"].toVariant().toBool(), | |||
490 | entry["name"].toString(), | |||
491 | entry["filter"].toString(), | |||
492 | fgColor, | |||
493 | bgColor, | |||
494 | root_); | |||
495 | rules.append(VariantPointer<ColoringRuleItem>::asQVariant(item)); | |||
496 | } | |||
497 | ||||
498 | insertRows(beginRow, static_cast<int>(rules.count()), QModelIndex()); | |||
499 | for (int i = 0; i < rules.count(); i++) { | |||
500 | QModelIndex idx = index(beginRow, 0, QModelIndex()); | |||
501 | setData(idx, rules[i], Qt::UserRole); | |||
502 | beginRow++; | |||
503 | } | |||
504 | ||||
505 | return true; | |||
506 | } | |||
507 | ||||
508 | QModelIndex ColoringRulesModel::index(int row, int column, const QModelIndex &parent) const | |||
509 | { | |||
510 | if (!hasIndex(row, column, parent)) | |||
511 | return QModelIndex(); | |||
512 | ||||
513 | ColoringRuleItem *parent_item, *child_item; | |||
514 | ||||
515 | if (!parent.isValid()) | |||
516 | parent_item = root_; | |||
517 | else | |||
518 | parent_item = static_cast<ColoringRuleItem*>(parent.internalPointer()); | |||
519 | ||||
520 | Q_ASSERT(parent_item)((parent_item) ? static_cast<void>(0) : qt_assert("parent_item" , "ui/qt/models/coloring_rules_model.cpp", 520)); | |||
521 | ||||
522 | child_item = parent_item->child(row); | |||
523 | if (child_item) { | |||
524 | return createIndex(row, column, child_item); | |||
525 | } | |||
526 | ||||
527 | return QModelIndex(); | |||
528 | } | |||
529 | ||||
530 | QModelIndex ColoringRulesModel::parent(const QModelIndex& indexItem) const | |||
531 | { | |||
532 | if (!indexItem.isValid()) | |||
533 | return QModelIndex(); | |||
534 | ||||
535 | ColoringRuleItem* item = static_cast<ColoringRuleItem*>(indexItem.internalPointer()); | |||
536 | if (item != NULL__null) { | |||
537 | ColoringRuleItem* parent_item = item->parentItem(); | |||
538 | if (parent_item != NULL__null) { | |||
539 | if (parent_item == root_) | |||
540 | return QModelIndex(); | |||
541 | ||||
542 | return createIndex(parent_item->row(), 0, parent_item); | |||
543 | } | |||
544 | } | |||
545 | ||||
546 | return QModelIndex(); | |||
547 | } | |||
548 | ||||
549 | int ColoringRulesModel::rowCount(const QModelIndex& parent) const | |||
550 | { | |||
551 | ColoringRuleItem *parent_item; | |||
552 | if (parent.column() > 0) | |||
553 | return 0; | |||
554 | ||||
555 | if (!parent.isValid()) | |||
556 | parent_item = root_; | |||
557 | else | |||
558 | parent_item = static_cast<ColoringRuleItem*>(parent.internalPointer()); | |||
559 | ||||
560 | if (parent_item == NULL__null) | |||
561 | return 0; | |||
562 | ||||
563 | return parent_item->childCount(); | |||
564 | } | |||
565 | ||||
566 | int ColoringRulesModel::columnCount(const QModelIndex&) const | |||
567 | { | |||
568 | return colColoringRulesMax; | |||
569 | } |