5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "main_window.h"
25 #include "ui_main_window.h"
29 #include <epan/epan_dissect.h>
30 #include <epan/filesystem.h>
31 #include <epan/ipproto.h>
32 #include <epan/prefs.h>
34 //#include <wiretap/wtap.h>
38 #include "capture-pcap-util.h"
39 #include "capture_ui_utils.h"
40 #include "capture_session.h"
43 #include "ui/alert_box.h"
44 #include "ui/capture_globals.h"
45 #include "ui/main_statusbar.h"
46 #include "ui/recent.h"
49 #include "wireshark_application.h"
50 #include "proto_tree.h"
51 #include "byte_view_tab.h"
52 #include "display_filter_edit.h"
53 #include "import_text_dialog.h"
54 #include "export_dissection_dialog.h"
56 #include "qt_ui_utils.h"
59 #include <QDesktopWidget>
61 #include <QMessageBox>
62 #include <QMetaObject>
63 #include <QPropertyAnimation>
65 #include <QToolButton>
66 #include <QTreeWidget>
68 #ifdef QT_MACEXTRAS_LIB
69 #include <QtMacExtras/QMacNativeToolBar>
74 //menu_recent_file_write_all
76 // If we ever add support for multiple windows this will need to be replaced.
77 static MainWindow *gbl_cur_main_window = NULL;
79 void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
81 gbl_cur_main_window->setPipeInputHandler(source, user_data, child_process, input_cb);
84 MainWindow::MainWindow(QWidget *parent) :
86 main_ui_(new Ui::MainWindow),
87 df_combo_box_(new DisplayFilterCombo()),
89 previous_focus_(NULL),
90 capture_stopping_(false),
91 capture_filter_valid_(false),
98 gbl_cur_main_window = this;
99 main_ui_->setupUi(this);
100 setTitlebarForCaptureFile();
101 setMenusForCaptureFile();
102 setForCapturedPackets(false);
103 setMenusForSelectedPacket();
104 setMenusForSelectedTreeRow();
105 setForCaptureInProgress(false);
106 setMenusForFileSet(false);
107 interfaceSelectionChanged();
109 //To prevent users use features before initialization complete
110 //Otherwise unexpected problems may occur
111 setFeaturesEnabled(false);
112 connect(wsApp, SIGNAL(appInitialized()), this, SLOT(setFeaturesEnabled()));
114 connect(wsApp, SIGNAL(preferencesChanged()), this, SLOT(layoutPanes()));
116 connect(wsApp, SIGNAL(recentFilesRead()), this, SLOT(loadWindowGeometry()));
118 connect(wsApp, SIGNAL(updateRecentItemStatus(const QString &, qint64, bool)), this, SLOT(updateRecentFiles()));
121 connect(&summary_dialog_, SIGNAL(captureCommentChanged()), this, SLOT(updateForUnsavedChanges()));
123 const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
124 connect(df_edit, SIGNAL(pushFilterSyntaxStatus(QString&)), main_ui_->statusBar, SLOT(pushFilterStatus(QString&)));
125 connect(df_edit, SIGNAL(popFilterSyntaxStatus()), main_ui_->statusBar, SLOT(popFilterStatus()));
126 connect(df_edit, SIGNAL(pushFilterSyntaxWarning(QString&)),
127 main_ui_->statusBar, SLOT(pushTemporaryStatus(QString&)));
128 connect(df_edit, SIGNAL(filterPackets(QString&,bool)), this, SLOT(filterPackets(QString&,bool)));
129 connect(df_edit, SIGNAL(addBookmark(QString)), this, SLOT(addDisplayFilterButton(QString)));
130 connect(this, SIGNAL(displayFilterSuccess(bool)), df_edit, SLOT(displayFilterSuccess(bool)));
132 // http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
133 // http://qt-project.org/doc/qt-4.8/qstyle.html#StandardPixmap-enum
134 main_ui_->actionFileOpen->setIcon(
135 QIcon().fromTheme("document-open", style()->standardIcon(QStyle::SP_DirIcon)));
136 // main_ui_->actionFileSave set in main_window.ui
137 main_ui_->actionFileClose->setIcon(
138 QIcon().fromTheme("process-stop", style()->standardIcon(QStyle::SP_DialogCloseButton)));
140 // In Qt4 multiple toolbars and "pretty" are mutually exculsive on OS X. If
141 // unifiedTitleAndToolBarOnMac is enabled everything ends up in the same row.
142 // https://bugreports.qt-project.org/browse/QTBUG-22433
143 // This property is obsolete in Qt5 so this issue may be fixed in that version.
144 main_ui_->displayFilterToolBar->addWidget(df_combo_box_);
146 main_ui_->goToFrame->hide();
147 // XXX For some reason the cursor is drawn funny with an input mask set
148 // https://bugreports.qt-project.org/browse/QTBUG-7174
150 main_ui_->searchFrame->hide();
151 connect(main_ui_->searchFrame, SIGNAL(pushFilterSyntaxStatus(QString&)),
152 main_ui_->statusBar, SLOT(pushTemporaryStatus(QString&)));
155 main_ui_->menuCapture->setEnabled(false);
158 #if defined(Q_OS_MAC)
159 #ifdef QT_MACEXTRAS_LIB
160 QMacNativeToolBar *ntb = QtMacExtras::setNativeToolBar(main_ui_->mainToolBar);
161 ntb->setIconSize(QSize(24, 24));
162 #endif // QT_MACEXTRAS_LIB
164 foreach (QMenu *menu, main_ui_->menuBar->findChildren<QMenu*>()) {
165 foreach (QAction *act, menu->actions()) {
166 act->setIconVisibleInMenu(false);
169 main_ui_->goToLineEdit->setAttribute(Qt::WA_MacSmallSize, true);
170 main_ui_->goToGo->setAttribute(Qt::WA_MacSmallSize, true);
171 main_ui_->goToCancel->setAttribute(Qt::WA_MacSmallSize, true);
173 main_ui_->actionEditPreferences->setMenuRole(QAction::PreferencesRole);
177 #ifdef HAVE_SOFTWARE_UPDATE
178 QAction *update_sep = main_ui_->menuHelp->insertSeparator(main_ui_->actionHelpAbout);
179 QAction *update_action = new QAction(tr("Check for Updates..."), main_ui_->menuHelp);
180 main_ui_->menuHelp->insertAction(update_sep, update_action);
181 connect(update_action, SIGNAL(triggered()), this, SLOT(on_actionHelpCheckForUpdates_triggered()));
183 master_split_.setObjectName(tr("splitterMaster"));
184 extra_split_.setObjectName(tr("splitterExtra"));
185 main_ui_->mainStack->addWidget(&master_split_);
187 empty_pane_.setObjectName(tr("emptyPane"));
189 packet_list_ = new PacketList(&master_split_);
191 proto_tree_ = new ProtoTree(&master_split_);
192 proto_tree_->setHeaderHidden(true);
193 proto_tree_->installEventFilter(this);
195 byte_view_tab_ = new ByteViewTab(&master_split_);
196 byte_view_tab_->setTabPosition(QTabWidget::South);
197 byte_view_tab_->setDocumentMode(true);
199 packet_list_->setProtoTree(proto_tree_);
200 packet_list_->setByteViewTab(byte_view_tab_);
201 packet_list_->installEventFilter(this);
203 main_welcome_ = main_ui_->welcomePage;
205 connect(wsApp, SIGNAL(captureCapturePrepared(capture_session *)),
206 this, SLOT(captureCapturePrepared(capture_session *)));
207 connect(wsApp, SIGNAL(captureCaptureUpdateStarted(capture_session *)),
208 this, SLOT(captureCaptureUpdateStarted(capture_session *)));
209 connect(wsApp, SIGNAL(captureCaptureUpdateFinished(capture_session *)),
210 this, SLOT(captureCaptureUpdateFinished(capture_session *)));
211 connect(wsApp, SIGNAL(captureCaptureFixedStarted(capture_session *)),
212 this, SLOT(captureCaptureFixedStarted(capture_session *)));
213 connect(wsApp, SIGNAL(captureCaptureFixedFinished(capture_session *)),
214 this, SLOT(captureCaptureFixedFinished(capture_session *)));
215 connect(wsApp, SIGNAL(captureCaptureStopping(capture_session *)),
216 this, SLOT(captureCaptureStopping(capture_session *)));
217 connect(wsApp, SIGNAL(captureCaptureFailed(capture_session *)),
218 this, SLOT(captureCaptureFailed(capture_session *)));
220 connect(wsApp, SIGNAL(captureFileOpened(const capture_file*)),
221 this, SLOT(captureFileOpened(const capture_file*)));
222 connect(wsApp, SIGNAL(captureFileReadStarted(const capture_file*)),
223 this, SLOT(captureFileReadStarted(const capture_file*)));
224 connect(wsApp, SIGNAL(captureFileReadFinished(const capture_file*)),
225 this, SLOT(captureFileReadFinished(const capture_file*)));
226 connect(wsApp, SIGNAL(captureFileClosing(const capture_file*)),
227 this, SLOT(captureFileClosing(const capture_file*)));
228 connect(wsApp, SIGNAL(captureFileClosed(const capture_file*)),
229 this, SLOT(captureFileClosed(const capture_file*)));
230 connect(wsApp, SIGNAL(columnsChanged()),
231 this, SLOT(recreatePacketList()));
232 connect(wsApp, SIGNAL(packetDissectionChanged()),
233 this, SLOT(redissectPackets()));
234 connect(wsApp, SIGNAL(appInitialized()),
235 this, SLOT(filterExpressionsChanged()));
236 connect(wsApp, SIGNAL(filterExpressionsChanged()),
237 this, SLOT(filterExpressionsChanged()));
239 connect(main_welcome_, SIGNAL(startCapture()),
240 this, SLOT(startCapture()));
241 connect(main_welcome_, SIGNAL(recentFileActivated(QString&)),
242 this, SLOT(openCaptureFile(QString&)));
243 connect(main_welcome_, SIGNAL(pushFilterSyntaxStatus(QString&)),
244 main_ui_->statusBar, SLOT(pushFilterStatus(QString&)));
245 connect(main_welcome_, SIGNAL(popFilterSyntaxStatus()),
246 main_ui_->statusBar, SLOT(popFilterStatus()));
248 connect(this, SIGNAL(setCaptureFile(capture_file*)),
249 main_ui_->searchFrame, SLOT(setCaptureFile(capture_file*)));
250 connect(this, SIGNAL(setCaptureFile(capture_file*)),
251 main_ui_->statusBar, SLOT(setCaptureFile(capture_file*)));
252 connect(this, SIGNAL(setCaptureFile(capture_file*)),
253 packet_list_, SLOT(setCaptureFile(capture_file*)));
254 connect(this, SIGNAL(setCaptureFile(capture_file*)),
255 byte_view_tab_, SLOT(setCaptureFile(capture_file*)));
257 connect(main_ui_->actionGoNextPacket, SIGNAL(triggered()),
258 packet_list_, SLOT(goNextPacket()));
259 connect(main_ui_->actionGoPreviousPacket, SIGNAL(triggered()),
260 packet_list_, SLOT(goPreviousPacket()));
261 connect(main_ui_->actionGoFirstPacket, SIGNAL(triggered()),
262 packet_list_, SLOT(goFirstPacket()));
263 connect(main_ui_->actionGoLastPacket, SIGNAL(triggered()),
264 packet_list_, SLOT(goLastPacket()));
266 connect(main_ui_->actionViewExpandSubtrees, SIGNAL(triggered()),
267 proto_tree_, SLOT(expandSubtrees()));
268 connect(main_ui_->actionViewExpandAll, SIGNAL(triggered()),
269 proto_tree_, SLOT(expandAll()));
270 connect(main_ui_->actionViewCollapseAll, SIGNAL(triggered()),
271 proto_tree_, SLOT(collapseAll()));
273 connect(packet_list_->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
274 this, SLOT(setMenusForSelectedPacket()));
275 connect(packet_list_, SIGNAL(packetDissectionChanged()),
276 this, SLOT(redissectPackets()));
277 connect(packet_list_, SIGNAL(setMenusFollowStream()),
278 this, SLOT(setMenusForFollowStream()));
280 connect(proto_tree_, SIGNAL(protoItemSelected(QString&)),
281 main_ui_->statusBar, SLOT(pushFieldStatus(QString&)));
283 connect(proto_tree_, SIGNAL(protoItemSelected(field_info *)),
284 this, SLOT(setMenusForSelectedTreeRow(field_info *)));
286 connect(&file_set_dialog_, SIGNAL(fileSetOpenCaptureFile(QString&)),
287 this, SLOT(openCaptureFile(QString&)));
289 QTreeWidget *iface_tree = findChild<QTreeWidget *>("interfaceTree");
291 connect(iface_tree, SIGNAL(itemSelectionChanged()),
292 this, SLOT(interfaceSelectionChanged()));
294 connect(main_ui_->welcomePage, SIGNAL(captureFilterSyntaxChanged(bool)),
295 this, SLOT(captureFilterSyntaxChanged(bool)));
297 main_ui_->mainStack->setCurrentWidget(main_welcome_);
300 MainWindow::~MainWindow()
305 QString MainWindow::getFilter()
307 return df_combo_box_->itemText(df_combo_box_->count());
310 void MainWindow::setPipeInputHandler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
312 pipe_source_ = source;
313 pipe_child_process_ = child_process;
314 pipe_user_data_ = user_data;
315 pipe_input_cb_ = input_cb;
318 /* Tricky to use pipes in win9x, as no concept of wait. NT can
319 do this but that doesn't cover all win32 platforms. GTK can do
320 this but doesn't seem to work over processes. Attempt to do
321 something similar here, start a timer and check for data on every
323 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
326 disconnect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout()));
330 pipe_timer_ = new QTimer(this);
331 connect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout()));
332 connect(pipe_timer_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed()));
333 pipe_timer_->start(200);
335 if (pipe_notifier_) {
336 disconnect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int)));
337 delete pipe_notifier_;
340 pipe_notifier_ = new QSocketNotifier(pipe_source_, QSocketNotifier::Read);
341 // XXX ui/gtk/gui_utils.c sets the encoding. Do we need to do the same?
342 connect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int)));
343 connect(pipe_notifier_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed()));
348 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
350 // The user typed some text. Start filling in a filter.
351 // We may need to be more choosy here. We just need to catch events for the packet list,
352 // proto tree, and main welcome widgets.
353 if (event->type() == QEvent::KeyPress) {
354 QKeyEvent *kevt = static_cast<QKeyEvent *>(event);
355 if (kevt->text().length() > 0 && kevt->text()[0].isPrint()) {
356 df_combo_box_->lineEdit()->insert(kevt->text());
357 df_combo_box_->lineEdit()->setFocus();
362 return QMainWindow::eventFilter(obj, event);
365 void MainWindow::keyPressEvent(QKeyEvent *event) {
367 // Explicitly focus on the display filter combo.
368 if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Slash) {
369 df_combo_box_->setFocus(Qt::ShortcutFocusReason);
373 if (wsApp->focusWidget() == main_ui_->goToLineEdit) {
374 if (event->modifiers() == Qt::NoModifier) {
375 if (event->key() == Qt::Key_Escape) {
376 on_goToCancel_clicked();
377 } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
381 return; // goToLineEdit didn't want it and we don't either.
384 // Move up & down the packet list.
385 if (event->key() == Qt::Key_F7) {
386 packet_list_->goPreviousPacket();
387 } else if (event->key() == Qt::Key_F8) {
388 packet_list_->goNextPacket();
391 // Move along, citizen.
392 QMainWindow::keyPressEvent(event);
395 void MainWindow::closeEvent(QCloseEvent *event) {
396 saveWindowGeometry();
398 /* If we're in the middle of stopping a capture, don't do anything;
399 the user can try deleting the window after the capture stops. */
400 if (capture_stopping_) {
405 // Make sure we kill any open dumpcap processes.
406 delete main_welcome_;
408 if(!wsApp->isInitialized()) {
409 // If we're still initializing, QCoreApplication::quit() won't
410 // exit properly because we are not in the event loop. This
411 // means that the application won't clean up after itself. We
412 // might want to call wsApp->processEvents() during startup
413 // instead so that we can do a normal exit here.
418 const int min_sensible_dimension = 200;
419 const int geom_animation_duration = 150;
420 void MainWindow::loadWindowGeometry()
422 QWidget shadow_main(wsApp->desktop());
423 shadow_main.setVisible(false);
425 // Start off with the Widget defaults
426 shadow_main.restoreGeometry(saveGeometry());
428 // Apply any saved settings
430 // Note that we're saving and restoring the outer window frame
431 // position and the inner client area size.
432 // if (prefs.gui_geometry_save_position) {
433 shadow_main.move(recent.gui_geometry_main_x, recent.gui_geometry_main_y);
436 // XXX Preferences haven't been loaded at this point. For now we
437 // assume default (true) values for everything.
439 if (// prefs.gui_geometry_save_size &&
440 recent.gui_geometry_main_width > min_sensible_dimension &&
441 recent.gui_geometry_main_width > min_sensible_dimension) {
442 shadow_main.resize(recent.gui_geometry_main_width, recent.gui_geometry_main_height);
445 // Let Qt move and resize our window if needed (e.g. if it's offscreen)
446 QByteArray geom = shadow_main.saveGeometry();
449 if (/* prefs.gui_geometry_save_maximized && */ recent.gui_geometry_main_maximized) {
450 setWindowState(Qt::WindowMaximized);
453 if (strlen (get_conn_cfilter()) < 1) {
454 QPropertyAnimation *pos_anim = new QPropertyAnimation(this, "pos");
455 QPropertyAnimation *size_anim = new QPropertyAnimation(this, "size");
457 shadow_main.restoreGeometry(geom);
459 pos_anim->setDuration(geom_animation_duration);
460 pos_anim->setStartValue(pos());
461 pos_anim->setEndValue(shadow_main.pos());
462 pos_anim->setEasingCurve(QEasingCurve::InOutQuad);
463 size_anim->setDuration(geom_animation_duration);
464 size_anim->setStartValue(size());
465 size_anim->setEasingCurve(QEasingCurve::InOutQuad);
466 size_anim->setEndValue(shadow_main.size());
468 pos_anim->start(QAbstractAnimation::DeleteWhenStopped);
469 size_anim->start(QAbstractAnimation::DeleteWhenStopped);
471 restoreGeometry(geom);
476 void MainWindow::saveWindowGeometry()
478 if (prefs.gui_geometry_save_position) {
479 recent.gui_geometry_main_x = pos().x();
480 recent.gui_geometry_main_y = pos().y();
483 if (prefs.gui_geometry_save_size) {
484 recent.gui_geometry_main_width = size().width();
485 recent.gui_geometry_main_height = size().height();
488 if (prefs.gui_geometry_save_maximized) {
489 // On OS X this is false when it shouldn't be
490 recent.gui_geometry_main_maximized = isMaximized();
494 QWidget* MainWindow::getLayoutWidget(layout_pane_content_e type) {
496 case layout_pane_content_none:
498 case layout_pane_content_plist:
500 case layout_pane_content_pdetails:
502 case layout_pane_content_pbytes:
503 return byte_view_tab_;
505 g_assert_not_reached();
510 void MainWindow::mergeCaptureFile()
512 QString file_name = "";
513 QString display_filter = "";
514 dfilter_t *rfcode = NULL;
520 if (prefs.gui_ask_unsaved) {
521 if (cf_has_unsaved_data(cap_file_)) {
522 QMessageBox msg_dialog;
523 gchar *display_basename;
526 msg_dialog.setIcon(QMessageBox::Question);
527 /* This file has unsaved data; ask the user whether to save
529 if (cap_file_->is_tempfile) {
530 msg_dialog.setText(tr("Save packets before merging?"));
531 msg_dialog.setInformativeText(tr("A temporary capture file can't be merged."));
534 * Format the message.
536 display_basename = g_filename_display_basename(cap_file_->filename);
537 msg_dialog.setText(QString(tr("Save changes in \"%1\" before merging?")).arg(display_basename));
538 g_free(display_basename);
539 msg_dialog.setInformativeText(tr("Changes must be saved before the files can be merged."));
542 msg_dialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
543 msg_dialog.setDefaultButton(QMessageBox::Save);
545 response = msg_dialog.exec();
549 case QMessageBox::Save:
550 /* Save the file but don't close it */
551 saveCaptureFile(cap_file_, FALSE);
554 case QMessageBox::Cancel:
556 /* Don't do the merge. */
563 CaptureFileDialog merge_dlg(this, cap_file_, display_filter);
565 cf_status_t merge_status;
566 char *in_filenames[2];
569 switch (prefs.gui_fileopen_style) {
571 case FO_STYLE_LAST_OPENED:
572 /* The user has specified that we should start out in the last directory
573 we looked in. If we've already opened a file, use its containing
574 directory, if we could determine it, as the directory, otherwise
575 use the "last opened" directory saved in the preferences file if
577 /* This is now the default behaviour in file_selection_new() */
580 case FO_STYLE_SPECIFIED:
581 /* The user has specified that we should always start out in a
582 specified directory; if they've specified that directory,
583 start out by showing the files in that dir. */
584 if (prefs.gui_fileopen_dir[0] != '\0')
585 merge_dlg.setDirectory(prefs.gui_fileopen_dir);
589 if (merge_dlg.merge(file_name)) {
590 if (dfilter_compile(display_filter.toUtf8().constData(), &rfcode)) {
591 cf_set_rfcode(cap_file_, rfcode);
593 /* Not valid. Tell the user, and go back and run the file
594 selection box again once they dismiss the alert. */
595 //bad_dfilter_alert_box(top_level, display_filter->str);
596 QMessageBox::warning(this, tr("Invalid Display Filter"),
597 QString(tr("The filter expression %1 isn't a valid display filter. (%2).").arg(display_filter, dfilter_error_msg)),
605 file_type = cap_file_->cd_t;
607 /* Try to merge or append the two files */
609 if (merge_dlg.mergeType() == 0) {
610 /* chronological order */
611 in_filenames[0] = cap_file_->filename;
612 in_filenames[1] = file_name.toUtf8().data();
613 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
614 } else if (merge_dlg.mergeType() <= 0) {
616 in_filenames[0] = file_name.toUtf8().data();
617 in_filenames[1] = cap_file_->filename;
618 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE);
621 in_filenames[0] = cap_file_->filename;
622 in_filenames[1] = file_name.toUtf8().data();
623 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE);
626 if (merge_status != CF_OK) {
628 dfilter_free(rfcode);
635 /* Try to open the merged capture file. */
637 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
638 /* We couldn't open it; fail. */
641 dfilter_free(rfcode);
646 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
647 it closed the previous capture file, and thus destroyed any
648 previous read filter attached to "cf"). */
649 cfile.rfcode = rfcode;
651 switch (cf_read(&cfile, FALSE)) {
655 /* Just because we got an error, that doesn't mean we were unable
656 to read any of the file; we handle what we could get from the
660 case CF_READ_ABORTED:
661 /* The user bailed out of re-reading the capture file; the
662 capture file has been closed - just free the capture file name
663 string and return (without changing the last containing
669 /* Save the name of the containing directory specified in the path name,
670 if any; we can write over cf_merged_name, which is a good thing, given that
671 "get_dirname()" does write over its argument. */
672 wsApp->setLastOpenDir(get_dirname(tmpname));
674 df_combo_box_->setEditText(display_filter);
675 main_ui_->statusBar->showExpert();
681 void MainWindow::importCaptureFile() {
682 ImportTextDialog import_dlg;
684 if (!testCaptureFileClose(FALSE, *new QString(tr(" before importing a new capture"))))
689 if (import_dlg.result() != QDialog::Accepted) {
690 main_ui_->mainStack->setCurrentWidget(main_welcome_);
694 openCaptureFile(import_dlg.capfileName());
697 void MainWindow::saveCaptureFile(capture_file *cf, bool stay_closed) {
699 gboolean discard_comments;
701 if (cf->is_tempfile) {
702 /* This is a temporary capture file, so saving it means saving
703 it to a permanent file. Prompt the user for a location
704 to which to save it. Don't require that the file format
705 support comments - if it's a temporary capture file, it's
706 probably pcap-ng, which supports comments and, if it's
707 not pcap-ng, let the user decide what they want to do
708 if they've added comments. */
709 saveAsCaptureFile(cf, FALSE, stay_closed);
711 if (cf->unsaved_changes) {
712 cf_write_status_t status;
714 /* This is not a temporary capture file, but it has unsaved
715 changes, so saving it means doing a "safe save" on top
716 of the existing file, in the same format - no UI needed
717 unless the file has comments and the file's format doesn't
720 If the file has comments, does the file's format support them?
721 If not, ask the user whether they want to discard the comments
722 or choose a different format. */
723 switch (CaptureFileDialog::checkSaveAsWithComments(this, cf, cf->cd_t)) {
726 /* The file can be saved in the specified format as is;
727 just drive on and save in the format they selected. */
728 discard_comments = FALSE;
731 case SAVE_WITHOUT_COMMENTS:
732 /* The file can't be saved in the specified format as is,
733 but it can be saved without the comments, and the user
734 said "OK, discard the comments", so save it in the
735 format they specified without the comments. */
736 discard_comments = TRUE;
739 case SAVE_IN_ANOTHER_FORMAT:
740 /* There are file formats in which we can save this that
741 support comments, and the user said not to delete the
742 comments. Do a "Save As" so the user can select
743 one of those formats and choose a file name. */
744 saveAsCaptureFile(cf, TRUE, stay_closed);
748 /* The user said "forget it". Just return. */
752 /* Squelch warnings that discard_comments is being used
754 g_assert_not_reached();
758 /* XXX - cf->filename might get freed out from under us, because
759 the code path through which cf_save_packets() goes currently
760 closes the current file and then opens and reloads the saved file,
761 so make a copy and free it later. */
762 file_name = cf->filename;
763 status = cf_save_packets(cf, file_name.toUtf8().constData(), cf->cd_t, cf->iscompressed,
764 discard_comments, stay_closed);
768 /* The save succeeded; we're done.
769 If we discarded comments, redraw the packet list to reflect
770 any packets that no longer have comments. */
771 if (discard_comments)
772 packet_list_queue_draw();
774 cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes
775 updateForUnsavedChanges(); // we update the title bar to remove the *
780 XXX - OK, what do we do now? Let them try a
781 "Save As", in case they want to try to save to a
782 different directory r file system? */
785 case CF_WRITE_ABORTED:
786 /* The write was aborted; just drive on. */
790 /* Otherwise just do nothing. */
794 void MainWindow::saveAsCaptureFile(capture_file *cf, bool must_support_comments, bool stay_closed) {
795 QString file_name = "";
798 cf_write_status_t status;
800 gboolean discard_comments = FALSE;
807 CaptureFileDialog save_as_dlg(this, cf);
809 switch (prefs.gui_fileopen_style) {
811 case FO_STYLE_LAST_OPENED:
812 /* The user has specified that we should start out in the last directory
813 we looked in. If we've already opened a file, use its containing
814 directory, if we could determine it, as the directory, otherwise
815 use the "last opened" directory saved in the preferences file if
817 /* This is now the default behaviour in file_selection_new() */
820 case FO_STYLE_SPECIFIED:
821 /* The user has specified that we should always start out in a
822 specified directory; if they've specified that directory,
823 start out by showing the files in that dir. */
824 if (prefs.gui_fileopen_dir[0] != '\0')
825 save_as_dlg.setDirectory(prefs.gui_fileopen_dir);
829 /* If the file has comments, does the format the user selected
830 support them? If not, ask the user whether they want to
831 discard the comments or choose a different format. */
832 switch(save_as_dlg.saveAs(file_name, must_support_comments)) {
835 /* The file can be saved in the specified format as is;
836 just drive on and save in the format they selected. */
837 discard_comments = FALSE;
840 case SAVE_WITHOUT_COMMENTS:
841 /* The file can't be saved in the specified format as is,
842 but it can be saved without the comments, and the user
843 said "OK, discard the comments", so save it in the
844 format they specified without the comments. */
845 discard_comments = TRUE;
848 case SAVE_IN_ANOTHER_FORMAT:
849 /* There are file formats in which we can save this that
850 support comments, and the user said not to delete the
851 comments. The combo box of file formats has had the
852 formats that don't support comments trimmed from it,
853 so run the dialog again, to let the user decide
854 whether to save in one of those formats or give up. */
855 discard_comments = FALSE;
856 must_support_comments = TRUE;
860 /* The user said "forget it". Just get rid of the dialog box
864 file_type = save_as_dlg.selectedFileType();
865 compressed = save_as_dlg.isCompressed();
867 fileAddExtension(file_name, file_type, compressed);
870 // /* If the file exists and it's user-immutable or not writable,
871 // ask the user whether they want to override that. */
872 // if (!file_target_unwritable_ui(top_level, file_name.toUtf8().constData())) {
873 // /* They don't. Let them try another file name or cancel. */
878 /* Attempt to save the file */
879 status = cf_save_packets(cf, file_name.toUtf8().constData(), file_type, compressed,
880 discard_comments, stay_closed);
884 /* The save succeeded; we're done. */
885 /* Save the directory name for future file dialogs. */
886 dirname = get_dirname(file_name.toUtf8().data()); /* Overwrites cf_name */
887 set_last_open_dir(dirname);
888 /* If we discarded comments, redraw the packet list to reflect
889 any packets that no longer have comments. */
890 if (discard_comments)
891 packet_list_queue_draw();
893 cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes
894 updateForUnsavedChanges(); // we update the title bar to remove the *
898 /* The save failed; let the user try again. */
901 case CF_WRITE_ABORTED:
902 /* The user aborted the save; just return. */
909 void MainWindow::exportSelectedPackets() {
910 QString file_name = "";
913 packet_range_t range;
914 cf_write_status_t status;
916 gboolean discard_comments = FALSE;
921 /* Init the packet range */
922 packet_range_init(&range, cap_file_);
923 range.process_filtered = TRUE;
924 range.include_dependents = TRUE;
927 CaptureFileDialog esp_dlg(this, cap_file_);
929 switch (prefs.gui_fileopen_style) {
931 case FO_STYLE_LAST_OPENED:
932 /* The user has specified that we should start out in the last directory
933 we looked in. If we've already opened a file, use its containing
934 directory, if we could determine it, as the directory, otherwise
935 use the "last opened" directory saved in the preferences file if
937 /* This is now the default behaviour in file_selection_new() */
940 case FO_STYLE_SPECIFIED:
941 /* The user has specified that we should always start out in a
942 specified directory; if they've specified that directory,
943 start out by showing the files in that dir. */
944 if (prefs.gui_fileopen_dir[0] != '\0')
945 esp_dlg.setDirectory(prefs.gui_fileopen_dir);
949 /* If the file has comments, does the format the user selected
950 support them? If not, ask the user whether they want to
951 discard the comments or choose a different format. */
952 switch(esp_dlg.exportSelectedPackets(file_name, &range)) {
955 /* The file can be saved in the specified format as is;
956 just drive on and save in the format they selected. */
957 discard_comments = FALSE;
960 case SAVE_WITHOUT_COMMENTS:
961 /* The file can't be saved in the specified format as is,
962 but it can be saved without the comments, and the user
963 said "OK, discard the comments", so save it in the
964 format they specified without the comments. */
965 discard_comments = TRUE;
968 case SAVE_IN_ANOTHER_FORMAT:
969 /* There are file formats in which we can save this that
970 support comments, and the user said not to delete the
971 comments. The combo box of file formats has had the
972 formats that don't support comments trimmed from it,
973 so run the dialog again, to let the user decide
974 whether to save in one of those formats or give up. */
975 discard_comments = FALSE;
979 /* The user said "forget it". Just get rid of the dialog box
985 * Check that we're not going to save on top of the current
987 * We do it here so we catch all cases ...
988 * Unfortunately, the file requester gives us an absolute file
989 * name and the read file name may be relative (if supplied on
990 * the command line). From Joerg Mayer.
992 if (files_identical(cap_file_->filename, file_name.toUtf8().constData())) {
994 gchar *display_basename = g_filename_display_basename(file_name.toUtf8().constData());
996 msg_box.setIcon(QMessageBox::Critical);
997 msg_box.setText(QString(tr("Unable to export to \"%1\".").arg(display_basename)));
998 msg_box.setInformativeText(tr("You cannot export packets to the current capture file."));
999 msg_box.setStandardButtons(QMessageBox::Ok);
1000 msg_box.setDefaultButton(QMessageBox::Ok);
1002 g_free(display_basename);
1006 file_type = esp_dlg.selectedFileType();
1007 compressed = esp_dlg.isCompressed();
1008 fileAddExtension(file_name, file_type, compressed);
1011 // /* If the file exists and it's user-immutable or not writable,
1012 // ask the user whether they want to override that. */
1013 // if (!file_target_unwritable_ui(top_level, file_name.toUtf8().constData())) {
1014 // /* They don't. Let them try another file name or cancel. */
1019 /* Attempt to save the file */
1020 status = cf_export_specified_packets(cap_file_, file_name.toUtf8().constData(), &range, file_type, compressed);
1024 /* The save succeeded; we're done. */
1025 /* Save the directory name for future file dialogs. */
1026 dirname = get_dirname(file_name.toUtf8().data()); /* Overwrites cf_name */
1027 set_last_open_dir(dirname);
1028 /* If we discarded comments, redraw the packet list to reflect
1029 any packets that no longer have comments. */
1030 if (discard_comments)
1031 packet_list_queue_draw();
1034 case CF_WRITE_ERROR:
1035 /* The save failed; let the user try again. */
1038 case CF_WRITE_ABORTED:
1039 /* The user aborted the save; just return. */
1046 void MainWindow::exportDissections(export_type_e export_type) {
1047 ExportDissectionDialog ed_dlg(this, cap_file_, export_type);
1048 packet_range_t range;
1053 /* Init the packet range */
1054 packet_range_init(&range, cap_file_);
1055 range.process_filtered = TRUE;
1056 range.include_dependents = TRUE;
1061 void MainWindow::fileAddExtension(QString &file_name, int file_type, bool compressed) {
1062 QString file_name_lower;
1063 QString file_suffix;
1064 GSList *extensions_list;
1065 gboolean add_extension;
1068 * Append the default file extension if there's none given by
1069 * the user or if they gave one that's not one of the valid
1070 * extensions for the file type.
1072 file_name_lower = file_name.toLower();
1073 extensions_list = wtap_get_file_extensions_list(file_type, FALSE);
1074 if (extensions_list != NULL) {
1077 /* We have one or more extensions for this file type.
1078 Start out assuming we need to add the default one. */
1079 add_extension = TRUE;
1081 /* OK, see if the file has one of those extensions. */
1082 for (extension = extensions_list; extension != NULL;
1083 extension = g_slist_next(extension)) {
1084 file_suffix += tr(".") + (char *)extension->data;
1085 if (file_name_lower.endsWith(file_suffix)) {
1087 * The file name has one of the extensions for
1090 add_extension = FALSE;
1093 file_suffix += ".gz";
1094 if (file_name_lower.endsWith(file_suffix)) {
1096 * The file name has one of the extensions for
1099 add_extension = FALSE;
1104 /* We have no extensions for this file type. Don't add one. */
1105 add_extension = FALSE;
1107 if (add_extension) {
1108 if (wtap_default_file_extension(file_type) != NULL) {
1109 file_name += tr(".") + wtap_default_file_extension(file_type);
1117 bool MainWindow::testCaptureFileClose(bool from_quit, QString &before_what) {
1118 bool capture_in_progress = FALSE;
1120 if (!cap_file_ || cap_file_->state == FILE_CLOSED)
1121 return true; /* Already closed, nothing to do */
1124 if (cap_file_->state == FILE_READ_IN_PROGRESS) {
1125 /* This is true if we're reading a capture file *or* if we're doing
1126 a live capture. If we're reading a capture file, the main loop
1127 is busy reading packets, and only accepting input from the
1128 progress dialog, so we can't get here, so this means we're
1130 capture_in_progress = TRUE;
1134 if (prefs.gui_ask_unsaved) {
1135 if (cf_has_unsaved_data(cap_file_) || capture_in_progress) {
1136 QMessageBox msg_dialog;
1138 QPushButton *saveButton;
1139 QPushButton *discardButton;
1141 msg_dialog.setIcon(QMessageBox::Question);
1143 /* This file has unsaved data or there's a capture in
1144 progress; ask the user whether to save the data. */
1145 if (cap_file_->is_tempfile) {
1147 msg_dialog.setText(tr("You have unsaved packets"));
1148 msg_dialog.setInformativeText(tr("They will be lost if you don't save them."));
1150 if (capture_in_progress) {
1151 question.append(tr("Do you want to stop the capture and save the captured packets"));
1153 question.append(tr("Do you want to save the captured packets"));
1155 question.append(before_what).append(tr("?"));
1156 msg_dialog.setInformativeText(question);
1161 * Format the message.
1163 if (capture_in_progress) {
1164 question.append(tr("Do you want to stop the capture and save the captured packets"));
1165 question.append(before_what).append(tr("?"));
1166 msg_dialog.setInformativeText(tr("Your captured packets will be lost if you don't save them."));
1168 gchar *display_basename = g_filename_display_basename(cap_file_->filename);
1169 question.append(QString(tr("Do you want to save the changes you've made to the capture file \"%1\"%2?"))
1170 .arg(display_basename)
1173 g_free(display_basename);
1174 msg_dialog.setInformativeText(tr("Your changes will be lost if you don't save them."));
1178 // XXX Text comes from ui/gtk/stock_icons.[ch]
1179 // Note that the button roles differ from the GTK+ version.
1180 // Cancel = RejectRole
1181 // Save = AcceptRole
1182 // Don't Save = DestructiveRole
1183 msg_dialog.addButton(QMessageBox::Cancel);
1185 if (capture_in_progress) {
1186 saveButton = msg_dialog.addButton(tr("Stop and Save"), QMessageBox::AcceptRole);
1188 saveButton = msg_dialog.addButton(QMessageBox::Save);
1190 msg_dialog.setDefaultButton(saveButton);
1193 if (cap_file_->state == FILE_READ_IN_PROGRESS) {
1194 discardButton = msg_dialog.addButton(tr("Stop and Quit without Saving"),
1195 QMessageBox::DestructiveRole);
1197 discardButton = msg_dialog.addButton(tr("Quit without Saving"),
1198 QMessageBox::DestructiveRole);
1201 if (capture_in_progress) {
1202 discardButton = msg_dialog.addButton(tr("Stop and Continue without Saving"),
1203 QMessageBox::DestructiveRole);
1205 discardButton = msg_dialog.addButton(QMessageBox::Discard);
1210 /* According to the Qt doc:
1211 * when using QMessageBox with custom buttons, exec() function returns an opaque value.
1213 * Therefore we should use clickedButton() to determine which button was clicked. */
1215 if(msg_dialog.clickedButton() == saveButton)
1218 /* If there's a capture in progress, we have to stop the capture
1219 and then do the save. */
1220 if (capture_in_progress)
1223 /* Save the file and close it */
1224 saveCaptureFile(cap_file_, TRUE);
1226 else if(msg_dialog.clickedButton() == discardButton)
1230 * If there's a capture in progress; we have to stop the capture
1231 * and then do the close.
1233 if (capture_in_progress)
1236 /* Just close the file, discarding changes */
1237 cf_close(cap_file_);
1240 else //cancelButton or some other unspecified button
1246 /* Unchanged file, just close it */
1247 cf_close(cap_file_);
1250 /* User asked not to be bothered by those prompts, just close it.
1251 XXX - should that apply only to saving temporary files? */
1253 /* If there's a capture in progress, we have to stop the capture
1254 and then do the close. */
1255 if (capture_in_progress)
1258 cf_close(cap_file_);
1261 return true; /* File closed */
1264 void MainWindow::captureStop() {
1267 while(cap_file_ && cap_file_->state == FILE_READ_IN_PROGRESS) {
1268 WiresharkApplication::processEvents();
1273 void MainWindow::setTitlebarForCaptureFile()
1275 if (cap_file_ && cap_file_->filename) {
1277 // Qt *REALLY* doesn't like windows that sometimes have a
1278 // title set with setWindowTitle() and other times have a
1279 // file path set; apparently, once you've set the title
1280 // with setWindowTitle(), it sticks, and setWindowFilePath()
1281 // has no effect. It appears to can clear the title with
1282 // setWindowTitle(NULL), but that clears the actual title in
1283 // the title bar, and setWindowFilePath() then, I guess, sees
1284 // that there's already a file path, and does nothing, leaving
1285 // the title bar empty. So you then have to clear the file path
1286 // with setWindowFilePath(NULL), and then set it.
1288 // Maybe there's a #include "you're holding it wrong" here.
1289 // However, I really don't want to hear from people who think
1290 // that a window can never be associated with something other
1291 // than a user file at time T1 and with a user file at time T2,
1292 // given that, in Wireshark, a window can be associated with a
1293 // live capture at time T1 and then, after you've saved the live
1294 // capture to a user file, associated with a user file at time T2.
1296 if (cap_file_->is_tempfile) {
1298 // For a temporary file, put the source of the data
1299 // in the window title, not whatever random pile
1300 // of characters is the last component of the path
1303 // XXX - on non-Mac platforms, put in the application
1307 setWindowFilePath(NULL);
1308 window_name = g_strdup_printf("Capturing from %s[*]", cf_get_tempfile_source(cap_file_)); //TODO : Fix Translate
1309 setWindowTitle(window_name);
1310 g_free(window_name);
1313 // For a user file, set the full path; that way,
1314 // for OS X, it'll set the "proxy icon". Qt
1315 // handles extracting the last component.
1317 // Sadly, some UN*Xes don't necessarily use UTF-8
1318 // for their file names, so we have to map the
1319 // file path to UTF-8. If that fails, we're somewhat
1322 char *utf8_filename = g_filename_to_utf8(cap_file_->filename,
1327 if (utf8_filename == NULL) {
1328 // So what the heck else can we do here?
1329 setWindowTitle(tr("(File name can't be mapped to UTF-8)"));
1331 setWindowTitle(NULL);
1332 setWindowFilePath(NULL);
1333 setWindowFilePath(utf8_filename);
1334 g_free(utf8_filename);
1337 setWindowModified(cf_has_unsaved_data(cap_file_));
1339 /* We have no capture file. */
1340 setWindowFilePath(NULL);
1341 setWindowTitle(tr("The Wireshark Network Analyzer"));
1345 void MainWindow::setTitlebarForSelectedTreeRow()
1347 setWindowTitle(tr("The Wireshark Network Analyzer"));
1351 void MainWindow::setTitlebarForCaptureInProgress()
1355 setWindowFilePath(NULL);
1357 window_name = g_strdup_printf("Capturing from %s", cf_get_tempfile_source(cap_file_)); //TODO : Fix Translate
1358 setWindowTitle(window_name);
1359 g_free(window_name);
1361 /* We have no capture in progress. */
1362 setWindowTitle(tr("The Wireshark Network Analyzer"));
1368 void MainWindow::setMenusForFollowStream()
1373 if (!cap_file_->edt)
1376 main_ui_->actionAnalyzeFollowTCPStream->setEnabled(false);
1377 main_ui_->actionAnalyzeFollowUDPStream->setEnabled(false);
1378 main_ui_->actionAnalyzeFollowSSLStream->setEnabled(false);
1380 if (cap_file_->edt->pi.ipproto == IP_PROTO_TCP)
1382 main_ui_->actionAnalyzeFollowTCPStream->setEnabled(true);
1385 if (cap_file_->edt->pi.ipproto == IP_PROTO_UDP)
1387 main_ui_->actionAnalyzeFollowUDPStream->setEnabled(true);
1390 if ( epan_dissect_packet_contains_field(cap_file_->edt, "ssl") )
1392 main_ui_->actionAnalyzeFollowSSLStream->setEnabled(true);
1396 /* Enable or disable menu items based on whether you have a capture file
1397 you've finished reading and, if you have one, whether it's been saved
1398 and whether it could be saved except by copying the raw packet data. */
1399 void MainWindow::setMenusForCaptureFile(bool force_disable)
1401 if (force_disable || cap_file_ == NULL || cap_file_->state == FILE_READ_IN_PROGRESS) {
1402 /* We have no capture file or we're currently reading a file */
1403 main_ui_->actionFileMerge->setEnabled(false);
1404 main_ui_->actionFileClose->setEnabled(false);
1405 main_ui_->actionFileSave->setEnabled(false);
1406 main_ui_->actionFileSaveAs->setEnabled(false);
1407 main_ui_->actionSummary->setEnabled(false);
1408 main_ui_->actionFileExportPackets->setEnabled(false);
1409 main_ui_->menuFileExportPacketDissections->setEnabled(false);
1410 main_ui_->actionFileExportPacketBytes->setEnabled(false);
1411 main_ui_->actionFileExportSSLSessionKeys->setEnabled(false);
1412 main_ui_->menuFileExportObjects->setEnabled(false);
1413 main_ui_->actionViewReload->setEnabled(false);
1415 main_ui_->actionFileMerge->setEnabled(cf_can_write_with_wiretap(cap_file_));
1417 main_ui_->actionFileClose->setEnabled(true);
1418 main_ui_->actionFileSave->setEnabled(cf_can_save(cap_file_));
1419 main_ui_->actionFileSaveAs->setEnabled(cf_can_save_as(cap_file_));
1420 main_ui_->actionSummary->setEnabled(true);
1422 * "Export Specified Packets..." should be available only if
1423 * we can write the file out in at least one format.
1425 main_ui_->actionFileExportPackets->setEnabled(cf_can_write_with_wiretap(cap_file_));
1426 main_ui_->menuFileExportPacketDissections->setEnabled(true);
1427 main_ui_->actionFileExportPacketBytes->setEnabled(true);
1428 main_ui_->actionFileExportSSLSessionKeys->setEnabled(true);
1429 main_ui_->menuFileExportObjects->setEnabled(true);
1430 main_ui_->actionViewReload->setEnabled(true);
1434 void MainWindow::setMenusForCaptureInProgress(bool capture_in_progress) {
1435 /* Either a capture was started or stopped; in either case, it's not
1436 in the process of stopping, so allow quitting. */
1438 main_ui_->actionFileOpen->setEnabled(!capture_in_progress);
1439 main_ui_->menuOpenRecentCaptureFile->setEnabled(!capture_in_progress);
1440 main_ui_->menuFileExportPacketDissections->setEnabled(capture_in_progress);
1441 main_ui_->actionFileExportPacketBytes->setEnabled(capture_in_progress);
1442 main_ui_->actionFileExportSSLSessionKeys->setEnabled(capture_in_progress);
1443 main_ui_->menuFileExportObjects->setEnabled(capture_in_progress);
1444 main_ui_->menuFileSet->setEnabled(!capture_in_progress);
1445 main_ui_->actionFileQuit->setEnabled(true);
1447 main_ui_->actionSummary->setEnabled(capture_in_progress);
1449 qDebug() << "FIX: packet list heading menu sensitivity";
1450 // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortAscending",
1451 // !capture_in_progress);
1452 // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortDescending",
1453 // !capture_in_progress);
1454 // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/NoSorting",
1455 // !capture_in_progress);
1458 main_ui_->actionCaptureOptions->setEnabled(!capture_in_progress);
1459 main_ui_->actionStartCapture->setEnabled(!capture_in_progress);
1460 main_ui_->actionStartCapture->setChecked(capture_in_progress);
1461 main_ui_->actionStopCapture->setEnabled(capture_in_progress);
1462 main_ui_->actionCaptureRestart->setEnabled(capture_in_progress);
1463 #endif /* HAVE_LIBPCAP */
1467 void MainWindow::setMenusForCaptureStopping() {
1468 main_ui_->actionFileQuit->setEnabled(false);
1469 main_ui_->actionSummary->setEnabled(false);
1471 main_ui_->actionStartCapture->setChecked(false);
1472 main_ui_->actionStopCapture->setEnabled(false);
1473 main_ui_->actionCaptureRestart->setEnabled(false);
1474 #endif /* HAVE_LIBPCAP */
1477 void MainWindow::setForCapturedPackets(bool have_captured_packets)
1479 main_ui_->actionFilePrint->setEnabled(have_captured_packets);
1481 // set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/Print",
1482 // have_captured_packets);
1484 main_ui_->actionEditFindPacket->setEnabled(have_captured_packets);
1485 main_ui_->actionEditFindNext->setEnabled(have_captured_packets);
1486 main_ui_->actionEditFindPrevious->setEnabled(have_captured_packets);
1487 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/ZoomIn",
1488 // have_captured_packets);
1489 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/ZoomOut",
1490 // have_captured_packets);
1491 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/NormalSize",
1492 // have_captured_packets);
1494 main_ui_->actionGoGoToPacket->setEnabled(have_captured_packets);
1495 main_ui_->actionGoPreviousPacket->setEnabled(have_captured_packets);
1496 main_ui_->actionGoNextPacket->setEnabled(have_captured_packets);
1497 main_ui_->actionGoFirstPacket->setEnabled(have_captured_packets);
1498 main_ui_->actionGoLastPacket->setEnabled(have_captured_packets);
1500 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/GoMenu/PreviousPacketInConversation",
1501 // have_captured_packets);
1502 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/GoMenu/NextPacketInConversation",
1503 // have_captured_packets);
1504 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/Summary",
1505 // have_captured_packets);
1506 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/ProtocolHierarchy",
1507 // have_captured_packets);
1510 void MainWindow::setMenusForFileSet(bool enable_list_files) {
1511 bool enable_next = fileset_get_next() != NULL && enable_list_files;
1512 bool enable_prev = fileset_get_previous() != NULL && enable_list_files;
1514 main_ui_->actionFileSetListFiles->setEnabled(enable_list_files);
1515 main_ui_->actionFileSetNextFile->setEnabled(enable_next);
1516 main_ui_->actionFileSetPreviousFile->setEnabled(enable_prev);
1519 void MainWindow::updateForUnsavedChanges() {
1520 setTitlebarForCaptureFile();
1521 setMenusForCaptureFile();
1522 // set_toolbar_for_capture_file(cf);
1526 /* Update main window items based on whether there's a capture in progress. */
1527 void MainWindow::setForCaptureInProgress(gboolean capture_in_progress)
1529 setMenusForCaptureInProgress(capture_in_progress);
1531 //#ifdef HAVE_LIBPCAP
1532 // set_toolbar_for_capture_in_progress(capture_in_progress);
1534 // set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
1544 * indent-tabs-mode: nil
1547 * ex: set shiftwidth=4 tabstop=8 expandtab:
1548 * :indentSize=4:tabSize=8:noTabs=true: