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 "simple_dialog.h"
14 #include "epan/strutil.h"
15 #include "epan/prefs.h"
17 #include "ui/commandline.h"
19 #include <wsutil/utf8_entities.h>
20 #include <wsutil/wslog.h>
22 #include <ui/qt/utils/qt_ui_utils.h>
23 #include "main_application.h"
27 #include <QMessageBox>
29 #include <QRegularExpression>
32 /* Simple dialog function - Displays a dialog box with the supplied message
35 * This is meant to be used as a backend for the functions defined in
36 * ui/simple_dialog.h. Qt code should use QMessageBox directly.
39 * type : One of ESD_TYPE_*.
40 * btn_mask : The value passed in determines which buttons are displayed.
41 * msg_format : Sprintf-style format of the text displayed in the dialog.
42 * ... : Argument list for msg_format
45 QList
<MessagePair
> message_queue_
;
46 ESD_TYPE_E max_severity_
= ESD_TYPE_INFO
;
48 struct VisibleAsyncMessage
53 VisibleAsyncMessage(QMessageBox
*box
) : box(box
), counter(0) {}
56 static QList
<VisibleAsyncMessage
> visible_messages
;
57 static QMutex visible_messages_mutex
;
59 static void visible_message_finished(QMessageBox
*box
, int result _U_
)
61 visible_messages_mutex
.lock();
62 for (int i
= 0; i
< visible_messages
.size(); i
++) {
63 if (visible_messages
[i
].box
== box
) {
64 if (visible_messages
[i
].counter
) {
65 ws_log(LOG_DOMAIN_MAIN
, LOG_LEVEL_WARNING
, "%d duplicates of \"%s\" were suppressed",
66 visible_messages
[i
].counter
, box
->text().toStdString().c_str());
68 visible_messages
.removeAt(i
);
72 visible_messages_mutex
.unlock();
76 simple_dialog_format_message(const char *msg
)
82 simple_dialog(ESD_TYPE_E type
, int btn_mask
, const char *msg_format
, ...)
86 va_start(ap
, msg_format
);
87 SimpleDialog
sd(mainApp
->mainWindow(), type
, btn_mask
, msg_format
, ap
);
95 simple_dialog_async(ESD_TYPE_E type
, int btn_mask
, const char *msg_format
, ...)
99 va_start(ap
, msg_format
);
100 SimpleDialog
sd(mainApp
->mainWindow(), type
, btn_mask
, msg_format
, ap
);
108 * Alert box, with optional "don't show this message again" variable
109 * and checkbox, and optional secondary text.
112 simple_message_box(ESD_TYPE_E type
, bool *notagain
,
113 const char *secondary_msg
, const char *msg_format
, ...)
115 if (notagain
&& *notagain
) {
121 va_start(ap
, msg_format
);
122 SimpleDialog
sd(mainApp
->mainWindow(), type
, ESD_BTN_OK
, msg_format
, ap
);
125 sd
.setInformativeText(secondary_msg
);
127 QCheckBox
*cb
= NULL
;
129 cb
= new QCheckBox();
130 cb
->setChecked(true);
131 cb
->setText(SimpleDialog::dontShowThisAgain());
137 if (notagain
&& cb
) {
138 *notagain
= cb
->isChecked();
143 * Error alert box, taking a format and a va_list argument.
146 vsimple_error_message_box(const char *msg_format
, va_list ap
)
149 // We want to quit after reading the capture file, hence
150 // we don't actually open the error dialog.
151 if (global_commandline_info
.quit_after_cap
)
155 SimpleDialog
sd(mainApp
->mainWindow(), ESD_TYPE_ERROR
, ESD_BTN_OK
, msg_format
, ap
);
160 * Warning alert box, taking a format and a va_list argument.
163 vsimple_warning_message_box(const char *msg_format
, va_list ap
)
166 // We want to quit after reading the capture file, hence
167 // we don't actually open the error dialog.
168 if (global_commandline_info
.quit_after_cap
)
172 SimpleDialog
sd(mainApp
->mainWindow(), ESD_TYPE_WARN
, ESD_BTN_OK
, msg_format
, ap
);
177 * Error alert box, taking a format and a list of arguments.
180 simple_error_message_box(const char *msg_format
, ...)
184 va_start(ap
, msg_format
);
185 vsimple_error_message_box(msg_format
, ap
);
189 SimpleDialog::SimpleDialog(QWidget
*parent
, ESD_TYPE_E type
, int btn_mask
, const char *msg_format
, va_list ap
) :
196 vmessage
= ws_strdup_vprintf(msg_format
, ap
);
199 // On Windows, filename strings inside Wireshark are UTF-8 strings,
200 // so error messages containing file names are UTF-8 strings. Convert
201 // from UTF-8, not from the local code page.
203 message
= QString().fromUtf8(vmessage
, -1);
206 // On UN*X, who knows? Assume the locale's encoding.
208 message
= QTextCodec::codecForLocale()->toUnicode(vmessage
);
212 MessagePair
msg_pair(message
, QString());
213 // Remove leading and trailing whitespace along with excessive newline runs.
214 QString primary
= msg_pair
.first
.trimmed();
215 QString secondary
= msg_pair
.second
.trimmed();
216 secondary
.replace(QRegularExpression("\n\n+"), "\n\n");
218 if (primary
.isEmpty()) {
222 if (!parent
|| !mainApp
->isInitialized() || mainApp
->isReloadingLua()) {
223 message_queue_
<< msg_pair
;
224 if (type
> max_severity_
) {
225 max_severity_
= type
;
230 message_box_
= new QMessageBox(parent
);
231 message_box_
->setTextFormat(Qt::PlainText
);
232 message_box_
->setTextInteractionFlags(Qt::TextSelectableByMouse
);
236 message_box_
->setIcon(QMessageBox::Critical
);
239 message_box_
->setIcon(QMessageBox::Warning
);
241 case ESD_TYPE_CONFIRMATION
:
242 message_box_
->setIcon(QMessageBox::Question
);
246 message_box_
->setIcon(QMessageBox::Information
);
250 if (btn_mask
& ESD_BTN_OK
) {
251 message_box_
->addButton(QMessageBox::Ok
);
253 if (btn_mask
& ESD_BTN_CANCEL
) {
254 message_box_
->addButton(QMessageBox::Cancel
);
256 if (btn_mask
& ESD_BTN_YES
) {
257 message_box_
->addButton(QMessageBox::Yes
);
259 if (btn_mask
& ESD_BTN_NO
) {
260 message_box_
->addButton(QMessageBox::No
);
262 // if (btn_mask & ESD_BTN_CLEAR) {
263 // addButton(QMessageBox::);
265 if (btn_mask
& ESD_BTN_SAVE
) {
266 message_box_
->addButton(QMessageBox::Save
);
268 if (btn_mask
& ESD_BTN_DONT_SAVE
) {
269 message_box_
->addButton(QMessageBox::Discard
);
271 // if (btn_mask & ESD_BTN_QUIT_DONT_SAVE) {
272 // addButton(QMessageBox::);
276 message_box_
->setText(primary
);
277 message_box_
->setInformativeText(secondary
);
280 SimpleDialog::~SimpleDialog()
284 void SimpleDialog::displayQueuedMessages(QWidget
*parent
)
286 if (message_queue_
.isEmpty()) {
290 QMessageBox
mb(parent
? parent
: mainApp
->mainWindow());
292 switch(max_severity_
) {
294 mb
.setIcon(QMessageBox::Critical
);
297 mb
.setIcon(QMessageBox::Warning
);
299 case ESD_TYPE_CONFIRMATION
:
300 mb
.setIcon(QMessageBox::Question
);
304 mb
.setIcon(QMessageBox::Information
);
308 mb
.addButton(QMessageBox::Ok
);
310 if (message_queue_
.length() > 1) {
311 QStringList msg_details
;
312 QString first_primary
= message_queue_
[0].first
;
313 first_primary
.append(UTF8_HORIZONTAL_ELLIPSIS
);
315 mb
.setText(QObject::tr("Multiple problems found"));
316 mb
.setInformativeText(first_primary
);
318 foreach (MessagePair msg_pair
, message_queue_
) {
319 msg_details
<< msg_pair
.first
;
320 if (!msg_pair
.second
.isEmpty()) {
321 msg_details
.append(msg_pair
.second
);
324 mb
.setDetailedText(msg_details
.join("\n\n"));
326 mb
.setText(message_queue_
[0].first
);
327 mb
.setInformativeText(message_queue_
[0].second
);
330 message_queue_
.clear();
331 max_severity_
= ESD_TYPE_INFO
;
336 QString
SimpleDialog::dontShowThisAgain()
338 return QObject::tr("Don't show this message again.");
341 int SimpleDialog::exec()
347 message_box_
->setInformativeText(informative_text_
);
348 message_box_
->setDetailedText(detailed_text_
);
349 message_box_
->setCheckBox(check_box_
);
351 int status
= message_box_
->exec();
354 informative_text_
= QString();
355 detailed_text_
= QString();
358 case QMessageBox::Ok
:
360 case QMessageBox::Yes
:
362 case QMessageBox::No
:
364 case QMessageBox::Save
:
366 case QMessageBox::Discard
:
367 return ESD_BTN_DONT_SAVE
;
368 case QMessageBox::Cancel
: // XXX Should OK be the default?
370 return ESD_BTN_CANCEL
;
374 void SimpleDialog::show()
380 message_box_
->setInformativeText(informative_text_
);
381 message_box_
->setDetailedText(detailed_text_
);
382 message_box_
->setCheckBox(check_box_
);
384 visible_messages_mutex
.lock();
386 for (int i
= 0; i
< visible_messages
.size(); i
++) {
387 VisibleAsyncMessage
&msg
= visible_messages
[i
];
388 if ((msg
.box
->icon() == message_box_
->icon()) &&
389 (msg
.box
->checkBox() == message_box_
->checkBox()) &&
390 (msg
.box
->text() == message_box_
->text()) &&
391 (msg
.box
->informativeText() == message_box_
->informativeText()) &&
392 (msg
.box
->detailedText() == message_box_
->detailedText()))
394 /* Message box of same type with same text is already visible. */
401 visible_messages
.append(VisibleAsyncMessage(message_box_
));
403 visible_messages_mutex
.unlock();
411 QObject::connect(message_box_
, &QMessageBox::finished
,
412 std::bind(visible_message_finished
,message_box_
,std::placeholders::_1
));
413 message_box_
->setModal(Qt::WindowModal
);
414 message_box_
->setAttribute(Qt::WA_DeleteOnClose
);
415 message_box_
->show();
418 /* Message box was shown and will be deleted once user closes it */