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
10 #include "uat_dialog.h"
11 #include <ui_uat_dialog.h>
12 #include "wireshark_application.h"
14 #include "epan/strutil.h"
15 #include "epan/uat-int.h"
16 #include "ui/help_url.h"
17 #include <wsutil/report_message.h>
19 #include <ui/qt/utils/qt_ui_utils.h>
21 #include <QDesktopServices>
22 #include <QPushButton>
27 // NOTE currently uat setter is always invoked in UatModel even if the uat checker fails.
29 UatDialog::UatDialog(QWidget *parent, epan_uat *uat) :
30 GeometryStateDialog(parent),
31 ui(new Ui::UatDialog),
37 if (uat) loadGeometry(0, 0, uat->name);
39 ui->deleteToolButton->setEnabled(false);
40 ui->copyToolButton->setEnabled(false);
41 ui->moveUpToolButton->setEnabled(false);
42 ui->moveDownToolButton->setEnabled(false);
43 ui->clearToolButton->setEnabled(false);
44 ok_button_ = ui->buttonBox->button(QDialogButtonBox::Ok);
45 help_button_ = ui->buttonBox->button(QDialogButtonBox::Help);
48 ui->newToolButton->setAttribute(Qt::WA_MacSmallSize, true);
49 ui->deleteToolButton->setAttribute(Qt::WA_MacSmallSize, true);
50 ui->copyToolButton->setAttribute(Qt::WA_MacSmallSize, true);
51 ui->moveUpToolButton->setAttribute(Qt::WA_MacSmallSize, true);
52 ui->moveDownToolButton->setAttribute(Qt::WA_MacSmallSize, true);
53 ui->clearToolButton->setAttribute(Qt::WA_MacSmallSize, true);
54 ui->pathLabel->setAttribute(Qt::WA_MacSmallSize, true);
59 // FIXME: this prevents the columns from being resized, even if the text
60 // within a combobox needs more space (e.g. in the USER DLT settings). For
61 // very long filenames in the SSL RSA keys dialog, it also results in a
62 // vertical scrollbar. Maybe remove this since the editor is not limited to
63 // the column width (and overlays other fields if more width is needed)?
64 ui->uatTreeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
66 // start editing as soon as the field is selected or when typing starts
67 ui->uatTreeView->setEditTriggers(ui->uatTreeView->editTriggers() |
68 QAbstractItemView::CurrentChanged | QAbstractItemView::AnyKeyPressed);
70 // Need to add uat_move or uat_insert to the UAT API.
71 ui->uatTreeView->setDragEnabled(false);
72 qDebug() << "FIX Add drag reordering to UAT dialog";
75 UatDialog::~UatDialog()
82 void UatDialog::setUat(epan_uat *uat)
84 QString title(tr("Unknown User Accessible Table"));
88 ui->pathLabel->clear();
89 ui->pathLabel->setEnabled(false);
90 help_button_->setEnabled(false);
97 QString abs_path = gchar_free_to_qstring(uat_get_actual_filename(uat_, FALSE));
98 ui->pathLabel->setText(abs_path);
99 ui->pathLabel->setUrl(QUrl::fromLocalFile(abs_path).toString());
100 ui->pathLabel->setToolTip(tr("Open ") + uat->filename);
101 ui->pathLabel->setEnabled(true);
103 uat_model_ = new UatModel(NULL, uat);
104 uat_delegate_ = new UatDelegate;
105 ui->uatTreeView->setModel(uat_model_);
106 ui->uatTreeView->setItemDelegate(uat_delegate_);
108 connect(uat_model_, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
109 this, SLOT(modelDataChanged(QModelIndex)));
110 connect(uat_model_, SIGNAL(rowsRemoved(QModelIndex, int, int)),
111 this, SLOT(modelRowsRemoved()));
112 connect(uat_model_, SIGNAL(modelReset()), this, SLOT(modelRowsReset()));
114 ok_button_->setEnabled(!uat_model_->hasErrors());
116 if (uat_->help && strlen(uat_->help) > 0) {
117 help_button_->setEnabled(true);
120 connect(this, SIGNAL(rejected()), this, SLOT(rejectChanges()));
121 connect(this, SIGNAL(accepted()), this, SLOT(acceptChanges()));
124 setWindowTitle(title);
127 // Invoked when a field in the model changes (e.g. by closing the editor)
128 void UatDialog::modelDataChanged(const QModelIndex &topLeft)
130 checkForErrorHint(topLeft, QModelIndex());
131 ok_button_->setEnabled(!uat_model_->hasErrors());
134 // Invoked after a row has been removed from the model.
135 void UatDialog::modelRowsRemoved()
137 const QModelIndex ¤t = ui->uatTreeView->currentIndex();
139 // Because currentItemChanged() is called before the row is removed from the model
140 // we also need to check for button enabling here.
141 if (current.isValid()) {
142 ui->moveUpToolButton->setEnabled(current.row() != 0);
143 ui->moveDownToolButton->setEnabled(current.row() != (uat_model_->rowCount() - 1));
145 ui->moveUpToolButton->setEnabled(false);
146 ui->moveDownToolButton->setEnabled(false);
149 checkForErrorHint(current, QModelIndex());
150 ok_button_->setEnabled(!uat_model_->hasErrors());
153 void UatDialog::modelRowsReset()
155 ui->deleteToolButton->setEnabled(false);
156 ui->clearToolButton->setEnabled(false);
157 ui->copyToolButton->setEnabled(false);
158 ui->moveUpToolButton->setEnabled(false);
159 ui->moveDownToolButton->setEnabled(false);
163 // Invoked when a different field is selected. Note: when selecting a different
164 // field after editing, this event is triggered after modelDataChanged.
165 void UatDialog::on_uatTreeView_currentItemChanged(const QModelIndex ¤t, const QModelIndex &previous)
167 if (current.isValid()) {
168 ui->deleteToolButton->setEnabled(true);
169 ui->clearToolButton->setEnabled(true);
170 ui->copyToolButton->setEnabled(true);
171 ui->moveUpToolButton->setEnabled(current.row() != 0);
172 ui->moveDownToolButton->setEnabled(current.row() != (uat_model_->rowCount() - 1));
174 ui->deleteToolButton->setEnabled(false);
175 ui->clearToolButton->setEnabled(false);
176 ui->copyToolButton->setEnabled(false);
177 ui->moveUpToolButton->setEnabled(false);
178 ui->moveDownToolButton->setEnabled(false);
181 checkForErrorHint(current, previous);
184 // If the current field has errors, show them.
185 // Otherwise if the row has not changed, but the previous field has errors, show them.
186 // Otherwise pick the first error in the current row.
187 // Otherwise show the error from the previous field (if any).
188 // Otherwise clear the error hint.
189 void UatDialog::checkForErrorHint(const QModelIndex ¤t, const QModelIndex &previous)
191 if (current.isValid()) {
192 if (trySetErrorHintFromField(current)) {
196 const int row = current.row();
197 if (row == previous.row() && trySetErrorHintFromField(previous)) {
201 for (int i = 0; i < uat_model_->columnCount(); i++) {
202 if (trySetErrorHintFromField(uat_model_->index(row, i))) {
208 if (previous.isValid()) {
209 if (trySetErrorHintFromField(previous)) {
214 ui->hintLabel->clear();
217 bool UatDialog::trySetErrorHintFromField(const QModelIndex &index)
219 const QVariant &data = uat_model_->data(index, Qt::UserRole + 1);
220 if (!data.isNull()) {
221 // use HTML instead of PlainText because that handles wordwrap properly
222 ui->hintLabel->setText("<small><i>" + html_escape(data.toString()) + "</i></small>");
228 void UatDialog::addRecord(bool copy_from_current)
232 const QModelIndex ¤t = ui->uatTreeView->currentIndex();
233 if (copy_from_current && !current.isValid()) return;
235 // should not fail, but you never know.
236 if (!uat_model_->insertRows(uat_model_->rowCount(), 1)) {
237 qDebug() << "Failed to add a new record";
240 const QModelIndex &new_index = uat_model_->index(uat_model_->rowCount() - 1, 0);
241 if (copy_from_current) {
242 uat_model_->copyRow(new_index.row(), current.row());
244 // due to an EditTrigger, this will also start editing.
245 ui->uatTreeView->setCurrentIndex(new_index);
246 // trigger updating error messages and the OK button state.
247 modelDataChanged(new_index);
250 void UatDialog::on_newToolButton_clicked()
255 void UatDialog::on_deleteToolButton_clicked()
257 const QModelIndex ¤t = ui->uatTreeView->currentIndex();
258 if (uat_model_ && current.isValid()) {
259 if (!uat_model_->removeRows(current.row(), 1)) {
260 qDebug() << "Failed to remove row";
265 void UatDialog::on_copyToolButton_clicked()
270 void UatDialog::on_moveUpToolButton_clicked()
272 const QModelIndex ¤t = ui->uatTreeView->currentIndex();
273 int current_row = current.row();
274 if (uat_model_ && current.isValid() && current_row > 0) {
275 if (!uat_model_->moveRow(current_row, current_row - 1)) {
276 qDebug() << "Failed to move row up";
280 ui->moveUpToolButton->setEnabled(current_row > 0);
281 ui->moveDownToolButton->setEnabled(current_row < (uat_model_->rowCount() - 1));
285 void UatDialog::on_moveDownToolButton_clicked()
287 const QModelIndex ¤t = ui->uatTreeView->currentIndex();
288 int current_row = current.row();
289 if (uat_model_ && current.isValid() && current_row < (uat_model_->rowCount() - 1)) {
290 if (!uat_model_->moveRow(current_row, current_row + 1)) {
291 qDebug() << "Failed to move row down";
295 ui->moveUpToolButton->setEnabled(current_row > 0);
296 ui->moveDownToolButton->setEnabled(current_row < (uat_model_->rowCount() - 1));
300 void UatDialog::on_clearToolButton_clicked()
303 uat_model_->clearAll();
307 void UatDialog::applyChanges()
311 if (uat_->flags & UAT_AFFECTS_FIELDS) {
312 /* Recreate list with new fields and redissect packets */
313 wsApp->queueAppSignal(WiresharkApplication::FieldsChanged);
315 if (uat_->flags & UAT_AFFECTS_DISSECTION) {
316 /* Just redissect packets if we have any */
317 wsApp->queueAppSignal(WiresharkApplication::PacketDissectionChanged);
322 void UatDialog::acceptChanges()
329 if (!uat_save(uat_, &err)) {
330 report_failure("Error while saving %s: %s", uat_->name, err);
334 if (uat_->post_update_cb) {
335 uat_->post_update_cb();
341 void UatDialog::rejectChanges()
348 if (!uat_load(uat_, &err)) {
349 report_failure("Error while loading %s: %s", uat_->name, err);
356 void UatDialog::on_buttonBox_helpRequested()
360 QString help_page = uat_->help, url;
362 help_page.append(".html");
363 url = gchar_free_to_qstring(user_guide_url(help_page.toUtf8().constData()));
365 QDesktopServices::openUrl(QUrl(url));
369 /* * Editor modelines
374 * indent-tabs-mode: nil
377 * ex: set shiftwidth=4 tabstop=8 expandtab:
378 * :indentSize=4:tabSize=8:noTabs=true: