Kerberos: add kerberos_inject_longterm_key() helper function
[wireshark-sm.git] / ui / qt / uat_frame.cpp
blob1a099feb133c97510dd8f4c22f8ad580f1cd2d7a
1 /* uat_frame.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
10 #include "config.h"
12 #include <epan/filter_expressions.h>
14 #include "uat_frame.h"
15 #include <ui_uat_frame.h>
16 #include <ui/qt/widgets/display_filter_edit.h>
17 #include "main_application.h"
19 #include <ui/qt/widgets/copy_from_profile_button.h>
20 #include <ui/qt/utils/qt_ui_utils.h>
21 #include <wsutil/report_message.h>
23 #include <QLineEdit>
24 #include <QKeyEvent>
25 #include <QTreeWidgetItemIterator>
26 #include <QUrl>
28 #include <QDebug>
30 UatFrame::UatFrame(QWidget *parent) :
31 QFrame(parent),
32 ui(new Ui::UatFrame),
33 uat_model_(NULL),
34 uat_delegate_(NULL),
35 uat_(NULL)
37 ui->setupUi(this);
39 ui->newToolButton->setStockIcon("list-add");
40 ui->deleteToolButton->setStockIcon("list-remove");
41 ui->copyToolButton->setStockIcon("list-copy");
42 ui->moveUpToolButton->setStockIcon("list-move-up");
43 ui->moveDownToolButton->setStockIcon("list-move-down");
44 ui->clearToolButton->setStockIcon("list-clear");
46 #ifdef Q_OS_MAC
47 ui->newToolButton->setAttribute(Qt::WA_MacSmallSize, true);
48 ui->deleteToolButton->setAttribute(Qt::WA_MacSmallSize, true);
49 ui->copyToolButton->setAttribute(Qt::WA_MacSmallSize, true);
50 ui->moveUpToolButton->setAttribute(Qt::WA_MacSmallSize, true);
51 ui->moveDownToolButton->setAttribute(Qt::WA_MacSmallSize, true);
52 ui->clearToolButton->setAttribute(Qt::WA_MacSmallSize, true);
53 ui->pathLabel->setAttribute(Qt::WA_MacSmallSize, true);
54 #endif
56 // FIXME: this prevents the columns from being resized, even if the text
57 // within a combobox needs more space (e.g. in the USER DLT settings). For
58 // very long filenames in the TLS RSA keys dialog, it also results in a
59 // vertical scrollbar. Maybe remove this since the editor is not limited to
60 // the column width (and overlays other fields if more width is needed)?
61 ui->uatTreeView->header()->setSectionResizeMode(QHeaderView::Interactive);
63 // start editing as soon as the field is selected or when typing starts
64 ui->uatTreeView->setEditTriggers(ui->uatTreeView->editTriggers() |
65 QAbstractItemView::CurrentChanged | QAbstractItemView::AnyKeyPressed);
68 UatFrame::~UatFrame()
70 delete ui;
71 delete uat_delegate_;
72 delete uat_model_;
75 void UatFrame::setUat(epan_uat *uat)
77 QString title(tr("Unknown User Accessible Table"));
79 uat_ = uat;
81 ui->pathLabel->clear();
82 ui->pathLabel->setEnabled(false);
84 if (uat_) {
85 if (uat_->name) {
86 title = uat_->name;
89 if (uat->from_profile) {
90 ui->copyFromProfileButton->setFilename(uat->filename);
91 connect(ui->copyFromProfileButton, &CopyFromProfileButton::copyProfile, this, &UatFrame::copyFromProfile);
94 QString abs_path = gchar_free_to_qstring(uat_get_actual_filename(uat_, false));
95 if (abs_path.length() > 0) {
96 ui->pathLabel->setText(abs_path);
97 ui->pathLabel->setUrl(QUrl::fromLocalFile(abs_path).toString());
98 ui->pathLabel->setToolTip(tr("Open ") + uat->filename);
99 } else {
100 ui->pathLabel->setText(uat_->filename);
102 ui->pathLabel->setEnabled(true);
104 uat_model_ = new UatModel(NULL, uat);
105 uat_delegate_ = new UatDelegate;
106 ui->uatTreeView->setModel(uat_model_);
107 ui->uatTreeView->setItemDelegate(uat_delegate_);
108 ui->uatTreeView->setSelectionMode(QAbstractItemView::ContiguousSelection);
109 resizeColumns();
110 ui->clearToolButton->setEnabled(uat_model_->rowCount() != 0);
112 connect(uat_model_, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
113 this, SLOT(modelDataChanged(QModelIndex)));
114 connect(uat_model_, SIGNAL(rowsRemoved(QModelIndex, int, int)),
115 this, SLOT(modelRowsRemoved()));
116 connect(uat_model_, SIGNAL(modelReset()), this, SLOT(modelRowsReset()));
118 connect(ui->uatTreeView->selectionModel(), &QItemSelectionModel::selectionChanged,
119 this, &UatFrame::uatTreeViewSelectionChanged);
122 setWindowTitle(title);
125 void UatFrame::copyFromProfile(QString filename)
127 char *err = NULL;
128 if (uat_load(uat_, filename.toUtf8().constData(), &err)) {
129 uat_->changed = true;
130 uat_model_->reloadUat();
131 } else {
132 report_failure("Error while loading %s: %s", uat_->name, err);
133 g_free(err);
137 void UatFrame::showEvent(QShowEvent *)
139 #ifndef Q_OS_MAC
140 ui->copyFromProfileButton->setFixedHeight(ui->copyToolButton->geometry().height());
141 #endif
144 void UatFrame::applyChanges()
146 if (!uat_) return;
148 if (uat_->flags & UAT_AFFECTS_FIELDS) {
149 /* Recreate list with new fields */
150 mainApp->queueAppSignal(MainApplication::FieldsChanged);
152 if (uat_->flags & UAT_AFFECTS_DISSECTION) {
153 /* Redissect packets if we have any */
154 mainApp->queueAppSignal(MainApplication::PacketDissectionChanged);
158 void UatFrame::acceptChanges()
160 if (!uat_model_) return;
162 QString error;
163 if (uat_model_->applyChanges(error)) {
164 if (!error.isEmpty()) {
165 report_failure("%s", qPrintable(error));
167 applyChanges();
171 void UatFrame::rejectChanges()
173 if (!uat_model_) return;
175 QString error;
176 if (uat_model_->revertChanges(error)) {
177 if (!error.isEmpty()) {
178 report_failure("%s", qPrintable(error));
183 void UatFrame::addRecord(bool copy_from_current)
185 if (!uat_) return;
187 QModelIndex current = ui->uatTreeView->currentIndex();
188 if (copy_from_current && !current.isValid()) return;
190 QModelIndex new_index;
191 if (copy_from_current) {
192 new_index = uat_model_->copyRow(current);
193 } else {
194 // should not fail, but you never know.
195 if (!uat_model_->insertRows(uat_model_->rowCount(), 1)) {
196 qDebug() << "Failed to add a new record";
197 return;
199 new_index = uat_model_->index(uat_model_->rowCount() - 1, 0);
202 // due to an EditTrigger, this will also start editing.
203 ui->uatTreeView->setCurrentIndex(new_index);
204 // trigger updating error messages and the OK button state.
205 modelDataChanged(new_index);
208 void UatFrame::uatTreeViewSelectionChanged(const QItemSelection&, const QItemSelection&)
210 QModelIndexList selectedRows = ui->uatTreeView->selectionModel()->selectedRows();
211 qsizetype num_selected = selectedRows.size();
212 if (num_selected > 0) {
213 std::sort(selectedRows.begin(), selectedRows.end());
214 ui->deleteToolButton->setEnabled(true);
215 ui->copyToolButton->setEnabled(true);
216 ui->moveUpToolButton->setEnabled(selectedRows.first().row() > 0);
217 ui->moveDownToolButton->setEnabled(selectedRows.last().row() < uat_model_->rowCount() - 1);
218 } else {
219 ui->deleteToolButton->setEnabled(false);
220 ui->copyToolButton->setEnabled(false);
221 ui->moveUpToolButton->setEnabled(false);
222 ui->moveDownToolButton->setEnabled(false);
226 // Invoked when a different field is selected. Note: when selecting a different
227 // field after editing, this event is triggered after modelDataChanged.
228 void UatFrame::on_uatTreeView_currentItemChanged(const QModelIndex &current, const QModelIndex &previous)
230 if (current.isValid()) {
231 ui->clearToolButton->setEnabled(true);
232 } else {
233 ui->clearToolButton->setEnabled(false);
236 checkForErrorHint(current, previous);
239 // Invoked when a field in the model changes (e.g. by closing the editor)
240 void UatFrame::modelDataChanged(const QModelIndex &topLeft)
242 checkForErrorHint(topLeft, QModelIndex());
243 resizeColumns();
246 // Invoked after a row has been removed from the model.
247 void UatFrame::modelRowsRemoved()
249 const QModelIndex &current = ui->uatTreeView->currentIndex();
251 // Because currentItemChanged() is called before the row is removed from the model
252 // we also need to check for button enabling here.
253 if (current.isValid()) {
254 ui->moveUpToolButton->setEnabled(current.row() != 0);
255 ui->moveDownToolButton->setEnabled(current.row() != (uat_model_->rowCount() - 1));
256 } else {
257 ui->moveUpToolButton->setEnabled(false);
258 ui->moveDownToolButton->setEnabled(false);
260 ui->clearToolButton->setEnabled(uat_model_->rowCount() != 0);
262 checkForErrorHint(current, QModelIndex());
265 void UatFrame::modelRowsReset()
267 ui->deleteToolButton->setEnabled(false);
268 ui->clearToolButton->setEnabled(uat_model_->rowCount() != 0);
269 ui->copyToolButton->setEnabled(false);
270 ui->moveUpToolButton->setEnabled(false);
271 ui->moveDownToolButton->setEnabled(false);
274 // If the current field has errors, show them.
275 // Otherwise if the row has not changed, but the previous field has errors, show them.
276 // Otherwise pick the first error in the current row.
277 // Otherwise show the error from the previous field (if any).
278 // Otherwise clear the error hint.
279 void UatFrame::checkForErrorHint(const QModelIndex &current, const QModelIndex &previous)
281 if (current.isValid()) {
282 if (trySetErrorHintFromField(current)) {
283 return;
286 const int row = current.row();
287 if (row == previous.row() && trySetErrorHintFromField(previous)) {
288 return;
291 for (int i = 0; i < uat_model_->columnCount(); i++) {
292 if (trySetErrorHintFromField(uat_model_->index(row, i))) {
293 return;
298 if (previous.isValid()) {
299 if (trySetErrorHintFromField(previous)) {
300 return;
304 ui->hintLabel->clear();
307 bool UatFrame::trySetErrorHintFromField(const QModelIndex &index)
309 const QVariant &data = uat_model_->data(index, Qt::UserRole + 1);
310 if (!data.isNull()) {
311 // use HTML instead of PlainText because that handles wordwrap properly
312 ui->hintLabel->setText("<small><i>" + html_escape(data.toString()) + "</i></small>");
313 return true;
315 return false;
318 void UatFrame::on_newToolButton_clicked()
320 addRecord();
323 void UatFrame::on_deleteToolButton_clicked()
325 if (uat_model_ == nullptr) {
326 return;
329 for (const auto &range : ui->uatTreeView->selectionModel()->selection()) {
330 // Each QItemSelectionRange is contiguous
331 if (!range.isEmpty()) {
332 if (!uat_model_->removeRows(range.top(), range.bottom() - range.top() + 1)) {
333 qDebug() << "Failed to remove rows" << range.top() << "to" << range.bottom();
339 void UatFrame::on_copyToolButton_clicked()
341 if (uat_model_ == nullptr) {
342 return;
345 QModelIndexList selectedRows = ui->uatTreeView->selectionModel()->selectedRows();
346 if (selectedRows.size() > 0) {
347 std::sort(selectedRows.begin(), selectedRows.end());
349 QModelIndex copyIdx;
351 for (const auto &idx : selectedRows) {
352 copyIdx = uat_model_->copyRow(idx);
353 if (!copyIdx.isValid())
355 qDebug() << "Failed to copy row" << idx.row();
357 // trigger updating error messages and the OK button state.
358 modelDataChanged(copyIdx);
360 // due to an EditTrigger, this will also start editing.
361 ui->uatTreeView->setCurrentIndex(copyIdx);
366 void UatFrame::on_moveUpToolButton_clicked()
368 if (uat_model_ == nullptr) {
369 return;
372 for (const auto &range : ui->uatTreeView->selectionModel()->selection()) {
373 // Each QItemSelectionRange is contiguous
374 if (!range.isEmpty() && range.top() > 0) {
375 // Swap range of rows with the row above the top
376 if (! uat_model_->moveRows(QModelIndex(), range.top(), range.bottom() - range.top() + 1, QModelIndex(), range.top() - 1)) {
377 qDebug() << "Failed to move up rows" << range.top() << "to" << range.bottom();
379 // Our moveRows implementation calls begin/endMoveRows(), so
380 // range.top() already has the new row number.
381 ui->moveUpToolButton->setEnabled(range.top() > 0);
382 ui->moveDownToolButton->setEnabled(true);
387 void UatFrame::on_moveDownToolButton_clicked()
389 if (uat_model_ == nullptr) {
390 return;
393 for (const auto &range : ui->uatTreeView->selectionModel()->selection()) {
394 // Each QItemSelectionRange is contiguous
395 if (!range.isEmpty() && range.bottom() + 1 < uat_model_->rowCount()) {
396 // Swap range of rows with the row below the top
397 if (! uat_model_->moveRows(QModelIndex(), range.top(), range.bottom() - range.top() + 1, QModelIndex(), range.bottom() + 1)) {
398 qDebug() << "Failed to move down rows" << range.top() << "to" << range.bottom();
400 // Our moveRows implementation calls begin/endMoveRows, so
401 // range.bottom() already has the new row number.
402 ui->moveUpToolButton->setEnabled(true);
403 ui->moveDownToolButton->setEnabled(range.bottom() < uat_model_->rowCount() - 1);
408 void UatFrame::on_clearToolButton_clicked()
410 if (uat_model_) {
411 uat_model_->clearAll();
415 void UatFrame::resizeColumns()
417 for (int i = 0; i < uat_model_->columnCount(); i++) {
418 ui->uatTreeView->resizeColumnToContents(i);
419 if (i == 0) {
420 ui->uatTreeView->setColumnWidth(i, ui->uatTreeView->columnWidth(i)+ui->uatTreeView->indentation());