Kerberos: add kerberos_inject_longterm_key() helper function
[wireshark-sm.git] / ui / qt / main_status_bar.cpp
blob5af3532277640d1469bc90644851bfe517ee0b93
1 /* main_status_bar.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 "file.h"
14 #include <epan/expert.h>
15 #include <epan/prefs.h>
17 #include <wsutil/filesystem.h>
18 #include <wsutil/utf8_entities.h>
20 #include "ui/main_statusbar.h"
21 #include <ui/qt/utils/qt_ui_utils.h>
22 #include <ui/qt/main_window.h>
24 #include "capture_file.h"
25 #include "main_status_bar.h"
26 #include "profile_dialog.h"
27 #include <ui/qt/utils/stock_icon.h>
28 #include <ui/qt/utils/color_utils.h>
29 #include <ui/qt/capture_file.h>
30 #include <ui/qt/widgets/clickable_label.h>
32 #include <QAction>
33 #include <QActionGroup>
34 #include <QHBoxLayout>
35 #include <QSplitter>
36 #include <QToolButton>
37 #include <QLatin1Char>
39 // To do:
40 // - Use the CaptureFile class.
42 // XXX - The GTK+ code assigns priorities to these and pushes/pops accordingly.
44 Q_DECLARE_METATYPE(ProfileDialog::ProfileAction)
46 // If we ever add support for multiple windows this will need to be replaced.
47 // See also: main_window.cpp
48 static MainStatusBar *cur_main_status_bar_;
51 * Push a formatted temporary message onto the statusbar.
53 void
54 statusbar_push_temporary_msg(const char *msg_format, ...)
56 va_list ap;
57 QString push_msg;
59 if (!cur_main_status_bar_) return;
61 va_start(ap, msg_format);
62 push_msg = QString::vasprintf(msg_format, ap);
63 va_end(ap);
65 mainApp->pushStatus(WiresharkApplication::TemporaryStatus, push_msg);
69 * Update the packets statusbar to the current values
71 void
72 packets_bar_update(void)
74 if (!cur_main_status_bar_) return;
76 cur_main_status_bar_->updateCaptureStatistics(NULL);
79 static const int icon_size = 14; // px
81 MainStatusBar::MainStatusBar(QWidget *parent) :
82 QStatusBar(parent),
83 cap_file_(NULL),
84 #ifdef HAVE_LIBPCAP
85 ready_msg_(tr("Ready to load or capture")),
86 #else
87 ready_msg_(tr("Ready to load file")),
88 #endif
89 cs_fixed_(false),
90 cs_count_(0)
92 QSplitter *splitter = new QSplitter(this);
93 QWidget *info_progress = new QWidget(this);
94 QHBoxLayout *info_progress_hb = new QHBoxLayout(info_progress);
96 #if defined(Q_OS_WIN)
97 // Handles are the same color as widgets, at least on Windows 7.
98 splitter->setHandleWidth(3);
99 splitter->setStyleSheet(QString(
100 "QSplitter::handle {"
101 " border-left: 1px solid palette(mid);"
102 " border-right: 1px solid palette(mid);"
105 #endif
107 #ifdef Q_OS_MAC
108 profile_status_.setAttribute(Qt::WA_MacSmallSize, true);
109 #endif
111 QString button_ss =
112 "QToolButton {"
113 " border: none;"
114 " background: transparent;" // Disables platform style on Windows.
115 " padding: 0px;"
116 " margin: 0px;"
117 "}";
119 expert_button_ = new QToolButton(this);
120 expert_button_->setIconSize(QSize(icon_size, icon_size));
121 expert_button_->setStyleSheet(button_ss);
122 expert_button_->hide();
124 // We just want a clickable image. Using a QPushButton or QToolButton would require
125 // a lot of adjustment.
126 StockIcon comment_icon("x-capture-comment-update");
127 comment_button_ = new QToolButton(this);
128 comment_button_->setIcon(comment_icon);
129 comment_button_->setIconSize(QSize(icon_size, icon_size));
130 comment_button_->setStyleSheet(button_ss);
132 comment_button_->setToolTip(tr("Open the Capture File Properties dialog"));
133 comment_button_->setEnabled(false);
134 connect(expert_button_, &QToolButton::clicked, this, &MainStatusBar::showExpertInfo);
135 connect(comment_button_, &QToolButton::clicked, this, &MainStatusBar::editCaptureComment);
137 info_progress_hb->setContentsMargins(icon_size / 2, 0, 0, 0);
139 info_status_.setTemporaryContext(STATUS_CTX_TEMPORARY);
140 info_status_.setShrinkable(true);
142 info_progress_hb->addWidget(expert_button_);
143 info_progress_hb->addWidget(comment_button_);
144 info_progress_hb->addWidget(&info_status_);
145 info_progress_hb->addWidget(&progress_frame_);
146 info_progress_hb->addStretch(10);
148 splitter->addWidget(info_progress);
149 splitter->addWidget(&packet_status_);
150 splitter->addWidget(&profile_status_);
152 splitter->setStretchFactor(0, 3);
153 splitter->setStretchFactor(1, 3);
154 splitter->setStretchFactor(2, 1);
156 addWidget(splitter, 1);
158 cur_main_status_bar_ = this;
160 splitter->hide();
161 info_status_.pushText(ready_msg_, STATUS_CTX_MAIN);
162 packets_bar_update();
164 #ifdef QWINTASKBARPROGRESS_H
165 progress_frame_.enableTaskbarUpdates(true);
166 #endif
168 connect(mainApp, &MainApplication::appInitialized, splitter, &QSplitter::show);
169 connect(mainApp, &MainApplication::appInitialized, this, &MainStatusBar::appInitialized);
170 connect(&info_status_, &LabelStack::toggleTemporaryFlash, this, &MainStatusBar::toggleBackground);
171 connect(mainApp, &MainApplication::profileNameChanged, this, &MainStatusBar::setProfileName);
172 connect(&profile_status_, &ClickableLabel::clickedAt, this, &MainStatusBar::showProfileMenu);
174 connect(&progress_frame_, &ProgressFrame::stopLoading, this, &MainStatusBar::stopLoading);
177 void MainStatusBar::showExpert() {
178 expertUpdate();
181 void MainStatusBar::captureFileClosing() {
182 expert_button_->hide();
183 progress_frame_.captureFileClosing();
184 popGenericStatus(STATUS_CTX_FIELD);
187 void MainStatusBar::expertUpdate() {
188 // <img> won't load @2x versions in Qt versions earlier than 5.4.
189 // https://bugreports.qt.io/browse/QTBUG-36383
190 // We might have to switch to a QPushButton.
191 QString stock_name = "x-expert-";
192 QString tt_text = tr(" is the highest expert information level");
194 switch(expert_get_highest_severity()) {
195 case(PI_ERROR):
196 stock_name.append("error");
197 tt_text.prepend(tr("ERROR"));
198 break;
199 case(PI_WARN):
200 stock_name.append("warn");
201 tt_text.prepend(tr("WARNING"));
202 break;
203 case(PI_NOTE):
204 stock_name.append("note");
205 tt_text.prepend(tr("NOTE"));
206 break;
207 case(PI_CHAT):
208 stock_name.append("chat");
209 tt_text.prepend(tr("CHAT"));
210 break;
211 // case(PI_COMMENT):
212 // m_expertStatus.setText("<img src=\":/expert/expert_comment.png\"></img>");
213 // break;
214 default:
215 stock_name.append("none");
216 tt_text = tr("No expert information");
217 break;
220 StockIcon expert_icon(stock_name);
221 expert_button_->setIcon(expert_icon);
222 expert_button_->setToolTip(tt_text);
223 expert_button_->show();
226 // ui/gtk/main_statusbar.c
227 void MainStatusBar::setFileName(CaptureFile &cf)
229 if (cf.isValid()) {
230 popGenericStatus(STATUS_CTX_FILE);
231 QString msgtip = QStringLiteral("%1 (%2)")
232 .arg(cf.capFile()->filename, file_size_to_qstring(cf.capFile()->f_datalen));
233 pushGenericStatus(STATUS_CTX_FILE, cf.fileName(), msgtip);
237 void MainStatusBar::changeEvent(QEvent *event)
239 if (event->type() == QEvent::LanguageChange) {
240 info_status_.popText(STATUS_CTX_MAIN);
241 info_status_.pushText(ready_msg_, STATUS_CTX_MAIN);
242 setStatusbarForCaptureFile();
243 showCaptureStatistics();
244 setProfileName();
246 QStatusBar::changeEvent(event);
249 void MainStatusBar::setCaptureFile(capture_file *cf)
251 cap_file_ = cf;
252 comment_button_->setEnabled(cap_file_ != NULL);
255 void MainStatusBar::setStatusbarForCaptureFile()
257 if (cap_file_ && cap_file_->filename && (cap_file_->state != FILE_CLOSED)) {
258 popGenericStatus(STATUS_CTX_FILE);
259 QString msgtip = QStringLiteral("%1 (%2)")
260 .arg(cap_file_->filename, file_size_to_qstring(cap_file_->f_datalen));
261 pushGenericStatus(STATUS_CTX_FILE,
262 gchar_free_to_qstring(cf_get_display_name(cap_file_)), msgtip);
266 void MainStatusBar::selectedFieldChanged(FieldInformation * finfo)
268 QString item_info;
270 if (! finfo) {
271 pushGenericStatus(STATUS_CTX_FIELD, item_info);
272 return;
275 FieldInformation::HeaderInfo hInfo = finfo->headerInfo();
277 if (hInfo.isValid)
279 if (hInfo.description.length() > 0) {
280 item_info.append(hInfo.description);
281 } else {
282 item_info.append(hInfo.name);
286 if (!item_info.isEmpty()) {
287 int finfo_length;
288 if (hInfo.isValid)
289 item_info.append(" (" + hInfo.abbreviation + ")");
291 finfo_length = finfo->position().length + finfo->appendix().length;
292 if (finfo_length > 0) {
293 int finfo_bits = FI_GET_BITS_SIZE(finfo->fieldInfo());
294 if (finfo_bits % 8 == 0) {
295 item_info.append(", " + tr("%Ln byte(s)", "", finfo_length));
296 } else {
297 item_info.append(", " + tr("%Ln bit(s)", "", finfo_bits));
302 pushGenericStatus(STATUS_CTX_FIELD, item_info);
305 void MainStatusBar::highlightedFieldChanged(FieldInformation * finfo)
307 QString hint;
309 if (finfo)
311 FieldInformation::Position pos = finfo->position();
313 if (pos.length < 2) {
314 hint = tr("Byte %1").arg(pos.start);
315 } else {
316 hint = tr("Bytes %1-%2").arg(pos.start).arg(pos.start + pos.length - 1);
318 hint += QStringLiteral(": %1 (%2)")
319 .arg(finfo->headerInfo().name, finfo->headerInfo().abbreviation);
322 pushGenericStatus(STATUS_CTX_BYTE, hint);
325 void MainStatusBar::pushGenericStatus(StatusContext status, const QString &message, const QString &messagetip)
327 LabelStack * stack = &info_status_;
329 if (status == STATUS_CTX_MAIN)
330 stack = &packet_status_;
332 if (message.isEmpty() && status != STATUS_CTX_FILE && status != STATUS_CTX_TEMPORARY && status != STATUS_CTX_PROGRESS)
333 popGenericStatus(status);
334 else
335 stack->pushText(message, status, messagetip);
337 if (status == STATUS_CTX_FILTER || status == STATUS_CTX_FILE)
338 expertUpdate();
341 void MainStatusBar::popGenericStatus(StatusContext status)
343 LabelStack * stack = &info_status_;
345 if (status == STATUS_CTX_MAIN)
346 stack = &packet_status_;
348 stack->popText(status);
351 void MainStatusBar::setProfileName()
353 profile_status_.setText(tr("Profile: %1").arg(get_profile_name()));
356 void MainStatusBar::appInitialized()
358 setProfileName();
359 connect(qobject_cast<MainWindow *>(mainApp->mainWindow()), &MainWindow::framesSelected, this, &MainStatusBar::selectedFrameChanged);
362 void MainStatusBar::selectedFrameChanged(QList<int>)
364 showCaptureStatistics();
367 void MainStatusBar::showCaptureStatistics()
369 QString packets_str;
371 QList<int> rows;
372 MainWindow * mw = qobject_cast<MainWindow *>(mainApp->mainWindow());
373 if (mw)
374 rows = mw->selectedRows(true);
376 #ifdef HAVE_LIBPCAP
377 if (cap_file_) {
378 /* Do we have any packets? */
379 if (!cs_fixed_) {
380 cs_count_ = cap_file_->count;
382 if (cs_count_ > 0) {
383 if (prefs.gui_show_selected_packet && rows.count() == 1) {
384 if (is_packet_configuration_namespace()) {
385 packets_str.append(tr("Selected Packet: %1 %2 ")
386 .arg(rows.at(0))
387 .arg(UTF8_MIDDLE_DOT));
388 } else {
389 packets_str.append(tr("Selected Event: %1 %2 ")
390 .arg(rows.at(0))
391 .arg(UTF8_MIDDLE_DOT));
394 if (is_packet_configuration_namespace()) {
395 packets_str.append(tr("Packets: %1")
396 .arg(cs_count_));
397 } else {
398 packets_str.append(tr("Events: %1")
399 .arg(cs_count_));
401 if (cap_file_->dfilter) {
402 packets_str.append(tr(" %1 Displayed: %2 (%3%)")
403 .arg(UTF8_MIDDLE_DOT)
404 .arg(cap_file_->displayed_count)
405 .arg((100.0*cap_file_->displayed_count)/cs_count_, 0, 'f', 1));
407 if (rows.count() > 1) {
408 packets_str.append(tr(" %1 Selected: %2 (%3%)")
409 .arg(UTF8_MIDDLE_DOT)
410 .arg(rows.count())
411 .arg((100.0*rows.count())/cs_count_, 0, 'f', 1));
413 if (cap_file_->marked_count > 0) {
414 packets_str.append(tr(" %1 Marked: %2 (%3%)")
415 .arg(UTF8_MIDDLE_DOT)
416 .arg(cap_file_->marked_count)
417 .arg((100.0*cap_file_->marked_count)/cs_count_, 0, 'f', 1));
419 if (cap_file_->drops_known) {
420 packets_str.append(tr(" %1 Dropped: %2 (%3%)")
421 .arg(UTF8_MIDDLE_DOT)
422 .arg(cap_file_->drops)
423 .arg((100.0*cap_file_->drops)/cs_count_, 0, 'f', 1));
425 if (cap_file_->ignored_count > 0) {
426 packets_str.append(tr(" %1 Ignored: %2 (%3%)")
427 .arg(UTF8_MIDDLE_DOT)
428 .arg(cap_file_->ignored_count)
429 .arg((100.0*cap_file_->ignored_count)/cs_count_, 0, 'f', 1));
431 if (cap_file_->packet_comment_count > 0) {
432 packets_str.append(tr(" %1 Comments: %2")
433 .arg(UTF8_MIDDLE_DOT)
434 .arg(cap_file_->packet_comment_count));
436 if (prefs.gui_show_file_load_time && !cap_file_->is_tempfile) {
437 /* Loading an existing file */
438 unsigned long computed_elapsed = cf_get_computed_elapsed(cap_file_);
439 packets_str.append(tr(" %1 Load time: %2:%3.%4")
440 .arg(UTF8_MIDDLE_DOT)
441 .arg(computed_elapsed/60000, 2, 10, QLatin1Char('0'))
442 .arg(computed_elapsed%60000/1000, 2, 10, QLatin1Char('0'))
443 .arg(computed_elapsed%1000, 3, 10, QLatin1Char('0')));
446 } else if (cs_fixed_ && cs_count_ > 0) {
447 /* There shouldn't be any rows without a cap_file_ but this is benign */
448 if (is_packet_configuration_namespace()) {
449 if (prefs.gui_show_selected_packet && rows.count() == 1) {
450 packets_str.append(tr("Selected Packet: %1 %2 ")
451 .arg(rows.at(0))
452 .arg(UTF8_MIDDLE_DOT));
454 packets_str.append(tr("Packets: %1")
455 .arg(cs_count_));
456 } else {
457 if (prefs.gui_show_selected_packet && rows.count() == 1) {
458 packets_str.append(tr("Selected Event: %1 %2 ")
459 .arg(rows.at(0))
460 .arg(UTF8_MIDDLE_DOT));
462 packets_str.append(tr("Events: %1")
463 .arg(cs_count_));
466 #endif // HAVE_LIBPCAP
468 if (packets_str.isEmpty()) {
469 if (is_packet_configuration_namespace()) {
470 packets_str = tr("No Packets");
471 } else {
472 packets_str = tr("No Events");
476 popGenericStatus(STATUS_CTX_MAIN);
477 pushGenericStatus(STATUS_CTX_MAIN, packets_str);
480 void MainStatusBar::updateCaptureStatistics(capture_session *cap_session)
482 cs_fixed_ = false;
484 #ifndef HAVE_LIBPCAP
485 Q_UNUSED(cap_session)
486 #else
487 if ((!cap_session || cap_session->cf == cap_file_) && cap_file_ && cap_file_->count) {
488 cs_count_ = cap_file_->count;
489 } else {
490 cs_count_ = 0;
492 #endif // HAVE_LIBPCAP
494 showCaptureStatistics();
497 void MainStatusBar::updateCaptureFixedStatistics(capture_session *cap_session)
499 cs_fixed_ = true;
501 #ifndef HAVE_LIBPCAP
502 Q_UNUSED(cap_session)
503 #else
504 if (cap_session && cap_session->count) {
505 cs_count_ = cap_session->count;
506 } else {
507 cs_count_ = 0;
509 #endif // HAVE_LIBPCAP
511 showCaptureStatistics();
514 void MainStatusBar::showProfileMenu(const QPoint &global_pos, Qt::MouseButton button)
516 ProfileModel model;
518 QMenu * ctx_menu_;
519 QMenu * profile_menu;
520 if (button == Qt::LeftButton) {
521 ctx_menu_ = nullptr;
522 profile_menu = new QMenu(this);
523 profile_menu->setAttribute(Qt::WA_DeleteOnClose);
524 } else {
525 ctx_menu_ = new QMenu(this);
526 ctx_menu_->setAttribute(Qt::WA_DeleteOnClose);
527 profile_menu = new QMenu(ctx_menu_);
529 QActionGroup * global = new QActionGroup(profile_menu);
530 QActionGroup * user = new QActionGroup(profile_menu);
532 for (int cnt = 0; cnt < model.rowCount(); cnt++)
534 QModelIndex idx = model.index(cnt, ProfileModel::COL_NAME);
535 if (! idx.isValid())
536 continue;
539 QAction * pa = Q_NULLPTR;
540 QString name = idx.data().toString();
542 // An ampersand in the menu item's text sets Alt+F as a shortcut for this menu.
543 // Use "&&" to get a real ampersand in the menu bar.
544 name.replace('&', "&&");
546 if (idx.data(ProfileModel::DATA_IS_DEFAULT).toBool())
548 pa = profile_menu->addAction(name);
550 else if (idx.data(ProfileModel::DATA_IS_GLOBAL).toBool())
552 /* Check if this profile does not exist as user */
553 if (cnt == model.findByName(name))
554 pa = global->addAction(name);
556 else
557 pa = user->addAction(name);
559 if (! pa)
560 continue;
562 pa->setCheckable(true);
563 if (idx.data(ProfileModel::DATA_IS_SELECTED).toBool())
564 pa->setChecked(true);
566 pa->setFont(idx.data(Qt::FontRole).value<QFont>());
567 pa->setProperty("profile_name", idx.data());
568 pa->setProperty("profile_is_global", idx.data(ProfileModel::DATA_IS_GLOBAL));
570 connect(pa, &QAction::triggered, this, &MainStatusBar::switchToProfile);
573 profile_menu->addActions(user->actions());
574 profile_menu->addSeparator();
575 profile_menu->addActions(global->actions());
577 if (button == Qt::LeftButton) {
578 profile_menu->popup(global_pos);
579 } else {
581 bool enable_edit = false;
583 QModelIndex idx = model.activeProfile();
584 if (! idx.data(ProfileModel::DATA_IS_DEFAULT).toBool() && ! idx.data(ProfileModel::DATA_IS_GLOBAL).toBool())
585 enable_edit = true;
587 profile_menu->setTitle(tr("Switch to"));
588 QAction * action = ctx_menu_->addAction(tr("Manage Profiles…"), this, SLOT(manageProfile()));
589 action->setProperty("dialog_action_", (int)ProfileDialog::ShowProfiles);
591 ctx_menu_->addSeparator();
592 action = ctx_menu_->addAction(tr("New…"), this, SLOT(manageProfile()));
593 action->setProperty("dialog_action_", (int)ProfileDialog::NewProfile);
594 action = ctx_menu_->addAction(tr("Edit…"), this, SLOT(manageProfile()));
595 action->setProperty("dialog_action_", (int)ProfileDialog::EditCurrentProfile);
596 action->setEnabled(enable_edit);
597 action = ctx_menu_->addAction(tr("Delete"), this, SLOT(manageProfile()));
598 action->setProperty("dialog_action_", (int)ProfileDialog::DeleteCurrentProfile);
599 action->setEnabled(enable_edit);
600 ctx_menu_->addSeparator();
602 #if defined(HAVE_MINIZIP) || defined(HAVE_MINIZIPNG)
603 QMenu * importMenu = new QMenu(tr("Import"), ctx_menu_);
604 action = importMenu->addAction(tr("From Zip File..."), this, SLOT(manageProfile()));
605 action->setProperty("dialog_action_", (int)ProfileDialog::ImportZipProfile);
606 action = importMenu->addAction(tr("From Directory..."), this, SLOT(manageProfile()));
607 action->setProperty("dialog_action_", (int)ProfileDialog::ImportDirProfile);
608 ctx_menu_->addMenu(importMenu);
610 if (model.userProfilesExist())
612 QMenu * exportMenu = new QMenu(tr("Export"), ctx_menu_);
613 if (enable_edit)
615 action = exportMenu->addAction(tr("Selected Personal Profile..."), this, SLOT(manageProfile()));
616 action->setProperty("dialog_action_", (int)ProfileDialog::ExportSingleProfile);
617 action->setEnabled(enable_edit);
619 action = exportMenu->addAction(tr("All Personal Profiles..."), this, SLOT(manageProfile()));
620 action->setProperty("dialog_action_", (int)ProfileDialog::ExportAllProfiles);
621 ctx_menu_->addMenu(exportMenu);
624 #else
625 action = ctx_menu_->addAction(tr("Import"), this, SLOT(manageProfile()));
626 action->setProperty("dialog_action_", (int)ProfileDialog::ImportDirProfile);
627 #endif
628 ctx_menu_->addSeparator();
630 ctx_menu_->addMenu(profile_menu);
631 ctx_menu_->popup(global_pos);
635 void MainStatusBar::toggleBackground(bool enabled)
637 if (enabled) {
638 setStyleSheet(QString(
639 "QStatusBar {"
640 " background-color: %2;"
643 .arg(ColorUtils::warningBackground().name()));
644 } else {
645 setStyleSheet(QString());
649 void MainStatusBar::switchToProfile()
651 QAction *pa = qobject_cast<QAction*>(sender());
653 if (pa && pa->property("profile_name").isValid()) {
654 QString profile = pa->property("profile_name").toString();
655 mainApp->setConfigurationProfile(profile.toUtf8().constData());
659 void MainStatusBar::manageProfile()
661 QAction *pa = qobject_cast<QAction*>(sender());
663 if (pa) {
664 ProfileDialog * cp_dialog = new ProfileDialog(this);
665 cp_dialog->setAttribute(Qt::WA_DeleteOnClose);
667 int profileAction = pa->property("dialog_action_").toInt();
668 cp_dialog->execAction(static_cast<ProfileDialog::ProfileAction>(profileAction));
672 void MainStatusBar::captureEventHandler(CaptureEvent ev)
674 switch(ev.captureContext())
676 #ifdef HAVE_LIBPCAP
677 case CaptureEvent::Update:
678 switch (ev.eventType())
680 case CaptureEvent::Continued:
681 updateCaptureStatistics(ev.capSession());
682 break;
683 case CaptureEvent::Finished:
684 updateCaptureStatistics(ev.capSession());
685 break;
686 default:
687 break;
689 break;
690 case CaptureEvent::Fixed:
691 switch (ev.eventType())
693 case CaptureEvent::Continued:
694 updateCaptureFixedStatistics(ev.capSession());
695 break;
696 default:
697 break;
699 break;
700 #endif
701 case CaptureEvent::Save:
702 switch (ev.eventType())
704 case CaptureEvent::Finished:
705 case CaptureEvent::Failed:
706 case CaptureEvent::Stopped:
707 popGenericStatus(STATUS_CTX_FILE);
708 break;
709 default:
710 break;
712 break;
713 default:
714 break;