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(updateRecentItemStatus(const QString &, qint64, bool)), this, SLOT(updateRecentFiles()));
119 connect(&summary_dialog_, SIGNAL(captureCommentChanged()), this, SLOT(updateForUnsavedChanges()));
120 connect(&follow_stream_dialog_, SIGNAL(updateFilter(QString&, bool)), this, SLOT(filterPackets(QString&, bool)));
122 const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
123 connect(df_edit, SIGNAL(pushFilterSyntaxStatus(QString&)), main_ui_->statusBar, SLOT(pushFilterStatus(QString&)));
124 connect(df_edit, SIGNAL(popFilterSyntaxStatus()), main_ui_->statusBar, SLOT(popFilterStatus()));
125 connect(df_edit, SIGNAL(pushFilterSyntaxWarning(QString&)),
126 main_ui_->statusBar, SLOT(pushTemporaryStatus(QString&)));
127 connect(df_edit, SIGNAL(filterPackets(QString&,bool)), this, SLOT(filterPackets(QString&,bool)));
128 connect(df_edit, SIGNAL(addBookmark(QString)), this, SLOT(addDisplayFilterButton(QString)));
129 connect(this, SIGNAL(displayFilterSuccess(bool)), df_edit, SLOT(displayFilterSuccess(bool)));
131 // http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
132 // http://qt-project.org/doc/qt-4.8/qstyle.html#StandardPixmap-enum
133 main_ui_->actionFileOpen->setIcon(
134 QIcon().fromTheme("document-open", style()->standardIcon(QStyle::SP_DirIcon)));
135 // main_ui_->actionFileSave set in main_window.ui
136 main_ui_->actionFileClose->setIcon(
137 QIcon().fromTheme("process-stop", style()->standardIcon(QStyle::SP_DialogCloseButton)));
139 // In Qt4 multiple toolbars and "pretty" are mutually exculsive on OS X. If
140 // unifiedTitleAndToolBarOnMac is enabled everything ends up in the same row.
141 // https://bugreports.qt-project.org/browse/QTBUG-22433
142 // This property is obsolete in Qt5 so this issue may be fixed in that version.
143 main_ui_->displayFilterToolBar->addWidget(df_combo_box_);
145 main_ui_->goToFrame->hide();
146 // XXX For some reason the cursor is drawn funny with an input mask set
147 // https://bugreports.qt-project.org/browse/QTBUG-7174
149 main_ui_->searchFrame->hide();
150 connect(main_ui_->searchFrame, SIGNAL(pushFilterSyntaxStatus(QString&)),
151 main_ui_->statusBar, SLOT(pushTemporaryStatus(QString&)));
154 main_ui_->menuCapture->setEnabled(false);
157 #if defined(Q_OS_MAC)
158 #ifdef QT_MACEXTRAS_LIB
159 QMacNativeToolBar *ntb = QtMacExtras::setNativeToolBar(main_ui_->mainToolBar);
160 ntb->setIconSize(QSize(24, 24));
161 #endif // QT_MACEXTRAS_LIB
163 foreach (QMenu *menu, main_ui_->menuBar->findChildren<QMenu*>()) {
164 foreach (QAction *act, menu->actions()) {
165 act->setIconVisibleInMenu(false);
168 main_ui_->goToLineEdit->setAttribute(Qt::WA_MacSmallSize, true);
169 main_ui_->goToGo->setAttribute(Qt::WA_MacSmallSize, true);
170 main_ui_->goToCancel->setAttribute(Qt::WA_MacSmallSize, true);
172 main_ui_->actionEditPreferences->setMenuRole(QAction::PreferencesRole);
176 #ifdef HAVE_SOFTWARE_UPDATE
177 QAction *update_sep = main_ui_->menuHelp->insertSeparator(main_ui_->actionHelpAbout);
178 QAction *update_action = new QAction(tr("Check for Updates..."), main_ui_->menuHelp);
179 main_ui_->menuHelp->insertAction(update_sep, update_action);
180 connect(update_action, SIGNAL(triggered()), this, SLOT(on_actionHelpCheckForUpdates_triggered()));
182 master_split_.setObjectName(tr("splitterMaster"));
183 extra_split_.setObjectName(tr("splitterExtra"));
184 main_ui_->mainStack->addWidget(&master_split_);
186 empty_pane_.setObjectName(tr("emptyPane"));
188 packet_list_ = new PacketList(&master_split_);
190 proto_tree_ = new ProtoTree(&master_split_);
191 proto_tree_->setHeaderHidden(true);
192 proto_tree_->installEventFilter(this);
194 byte_view_tab_ = new ByteViewTab(&master_split_);
195 byte_view_tab_->setTabPosition(QTabWidget::South);
196 byte_view_tab_->setDocumentMode(true);
198 packet_list_->setProtoTree(proto_tree_);
199 packet_list_->setByteViewTab(byte_view_tab_);
200 packet_list_->installEventFilter(this);
202 main_welcome_ = main_ui_->welcomePage;
204 connect(wsApp, SIGNAL(captureCapturePrepared(capture_session *)),
205 this, SLOT(captureCapturePrepared(capture_session *)));
206 connect(wsApp, SIGNAL(captureCaptureUpdateStarted(capture_session *)),
207 this, SLOT(captureCaptureUpdateStarted(capture_session *)));
208 connect(wsApp, SIGNAL(captureCaptureUpdateFinished(capture_session *)),
209 this, SLOT(captureCaptureUpdateFinished(capture_session *)));
210 connect(wsApp, SIGNAL(captureCaptureFixedStarted(capture_session *)),
211 this, SLOT(captureCaptureFixedStarted(capture_session *)));
212 connect(wsApp, SIGNAL(captureCaptureFixedFinished(capture_session *)),
213 this, SLOT(captureCaptureFixedFinished(capture_session *)));
214 connect(wsApp, SIGNAL(captureCaptureStopping(capture_session *)),
215 this, SLOT(captureCaptureStopping(capture_session *)));
216 connect(wsApp, SIGNAL(captureCaptureFailed(capture_session *)),
217 this, SLOT(captureCaptureFailed(capture_session *)));
219 connect(wsApp, SIGNAL(captureFileOpened(const capture_file*)),
220 this, SLOT(captureFileOpened(const capture_file*)));
221 connect(wsApp, SIGNAL(captureFileReadStarted(const capture_file*)),
222 this, SLOT(captureFileReadStarted(const capture_file*)));
223 connect(wsApp, SIGNAL(captureFileReadFinished(const capture_file*)),
224 this, SLOT(captureFileReadFinished(const capture_file*)));
225 connect(wsApp, SIGNAL(captureFileClosing(const capture_file*)),
226 this, SLOT(captureFileClosing(const capture_file*)));
227 connect(wsApp, SIGNAL(captureFileClosed(const capture_file*)),
228 this, SLOT(captureFileClosed(const capture_file*)));
229 connect(wsApp, SIGNAL(columnsChanged()),
230 this, SLOT(recreatePacketList()));
231 connect(wsApp, SIGNAL(packetDissectionChanged()),
232 this, SLOT(redissectPackets()));
233 connect(wsApp, SIGNAL(appInitialized()),
234 this, SLOT(filterExpressionsChanged()));
235 connect(wsApp, SIGNAL(filterExpressionsChanged()),
236 this, SLOT(filterExpressionsChanged()));
238 connect(main_welcome_, SIGNAL(startCapture()),
239 this, SLOT(startCapture()));
240 connect(main_welcome_, SIGNAL(recentFileActivated(QString&)),
241 this, SLOT(openCaptureFile(QString&)));
242 connect(main_welcome_, SIGNAL(pushFilterSyntaxStatus(QString&)),
243 main_ui_->statusBar, SLOT(pushFilterStatus(QString&)));
244 connect(main_welcome_, SIGNAL(popFilterSyntaxStatus()),
245 main_ui_->statusBar, SLOT(popFilterStatus()));
247 connect(this, SIGNAL(setCaptureFile(capture_file*)),
248 main_ui_->searchFrame, SLOT(setCaptureFile(capture_file*)));
249 connect(this, SIGNAL(setCaptureFile(capture_file*)),
250 main_ui_->statusBar, SLOT(setCaptureFile(capture_file*)));
251 connect(this, SIGNAL(setCaptureFile(capture_file*)),
252 packet_list_, SLOT(setCaptureFile(capture_file*)));
253 connect(this, SIGNAL(setCaptureFile(capture_file*)),
254 byte_view_tab_, SLOT(setCaptureFile(capture_file*)));
256 connect(main_ui_->actionGoNextPacket, SIGNAL(triggered()),
257 packet_list_, SLOT(goNextPacket()));
258 connect(main_ui_->actionGoPreviousPacket, SIGNAL(triggered()),
259 packet_list_, SLOT(goPreviousPacket()));
260 connect(main_ui_->actionGoFirstPacket, SIGNAL(triggered()),
261 packet_list_, SLOT(goFirstPacket()));
262 connect(main_ui_->actionGoLastPacket, SIGNAL(triggered()),
263 packet_list_, SLOT(goLastPacket()));
265 connect(main_ui_->actionViewExpandSubtrees, SIGNAL(triggered()),
266 proto_tree_, SLOT(expandSubtrees()));
267 connect(main_ui_->actionViewExpandAll, SIGNAL(triggered()),
268 proto_tree_, SLOT(expandAll()));
269 connect(main_ui_->actionViewCollapseAll, SIGNAL(triggered()),
270 proto_tree_, SLOT(collapseAll()));
272 connect(packet_list_->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
273 this, SLOT(setMenusForSelectedPacket()));
274 connect(packet_list_, SIGNAL(packetDissectionChanged()),
275 this, SLOT(redissectPackets()));
276 connect(packet_list_, SIGNAL(setMenusFollowStream()),
277 this, SLOT(setMenusForFollowStream()));
279 connect(proto_tree_, SIGNAL(protoItemSelected(QString&)),
280 main_ui_->statusBar, SLOT(pushFieldStatus(QString&)));
282 connect(proto_tree_, SIGNAL(protoItemSelected(field_info *)),
283 this, SLOT(setMenusForSelectedTreeRow(field_info *)));
285 connect(&file_set_dialog_, SIGNAL(fileSetOpenCaptureFile(QString&)),
286 this, SLOT(openCaptureFile(QString&)));
288 QTreeWidget *iface_tree = findChild<QTreeWidget *>("interfaceTree");
290 connect(iface_tree, SIGNAL(itemSelectionChanged()),
291 this, SLOT(interfaceSelectionChanged()));
293 connect(main_ui_->welcomePage, SIGNAL(captureFilterSyntaxChanged(bool)),
294 this, SLOT(captureFilterSyntaxChanged(bool)));
296 main_ui_->mainStack->setCurrentWidget(main_welcome_);
299 MainWindow::~MainWindow()
304 QString MainWindow::getFilter()
306 return df_combo_box_->itemText(df_combo_box_->count());
309 void MainWindow::setPipeInputHandler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
311 pipe_source_ = source;
312 pipe_child_process_ = child_process;
313 pipe_user_data_ = user_data;
314 pipe_input_cb_ = input_cb;
317 /* Tricky to use pipes in win9x, as no concept of wait. NT can
318 do this but that doesn't cover all win32 platforms. GTK can do
319 this but doesn't seem to work over processes. Attempt to do
320 something similar here, start a timer and check for data on every
322 /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
325 disconnect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout()));
329 pipe_timer_ = new QTimer(this);
330 connect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout()));
331 connect(pipe_timer_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed()));
332 pipe_timer_->start(200);
334 if (pipe_notifier_) {
335 disconnect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int)));
336 delete pipe_notifier_;
339 pipe_notifier_ = new QSocketNotifier(pipe_source_, QSocketNotifier::Read);
340 // XXX ui/gtk/gui_utils.c sets the encoding. Do we need to do the same?
341 connect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int)));
342 connect(pipe_notifier_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed()));
347 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
349 // The user typed some text. Start filling in a filter.
350 // We may need to be more choosy here. We just need to catch events for the packet list,
351 // proto tree, and main welcome widgets.
352 if (event->type() == QEvent::KeyPress) {
353 QKeyEvent *kevt = static_cast<QKeyEvent *>(event);
354 if (kevt->text().length() > 0 && kevt->text()[0].isPrint()) {
355 df_combo_box_->lineEdit()->insert(kevt->text());
356 df_combo_box_->lineEdit()->setFocus();
361 return QObject::eventFilter(obj, event);
364 void MainWindow::keyPressEvent(QKeyEvent *event) {
366 // Explicitly focus on the display filter combo.
367 if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Slash) {
368 df_combo_box_->setFocus(Qt::ShortcutFocusReason);
372 if (wsApp->focusWidget() == main_ui_->goToLineEdit) {
373 if (event->modifiers() == Qt::NoModifier) {
374 if (event->key() == Qt::Key_Escape) {
375 on_goToCancel_clicked();
376 } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
380 return; // goToLineEdit didn't want it and we don't either.
383 // Move up & down the packet list.
384 if (event->key() == Qt::Key_F7) {
385 packet_list_->goPreviousPacket();
386 } else if (event->key() == Qt::Key_F8) {
387 packet_list_->goNextPacket();
390 // Move along, citizen.
391 QMainWindow::keyPressEvent(event);
394 void MainWindow::closeEvent(QCloseEvent *event) {
395 saveWindowGeometry();
397 /* If we're in the middle of stopping a capture, don't do anything;
398 the user can try deleting the window after the capture stops. */
399 if (capture_stopping_) {
404 // Make sure we kill any open dumpcap processes.
405 delete main_welcome_;
407 if(!wsApp->isInitialized()) {
408 // If we're still initializing, QCoreApplication::quit() won't
409 // exit properly because we are not in the event loop. This
410 // means that the application won't clean up after itself. We
411 // might want to call wsApp->processEvents() during startup
412 // instead so that we can do a normal exit here.
417 const int min_sensible_dimension = 200;
418 const int geom_animation_duration = 150;
419 void MainWindow::loadWindowGeometry()
421 QWidget shadow_main(wsApp->desktop());
422 shadow_main.setVisible(false);
424 // Start off with the Widget defaults
425 shadow_main.restoreGeometry(saveGeometry());
427 // Apply any saved settings
429 // Note that we're saving and restoring the outer window frame
430 // position and the inner client area size.
431 if (prefs.gui_geometry_save_position) {
432 shadow_main.move(recent.gui_geometry_main_x, recent.gui_geometry_main_y);
435 // XXX Preferences haven't been loaded at this point. For now we
436 // assume default (true) values for everything.
438 if (// prefs.gui_geometry_save_size &&
439 recent.gui_geometry_main_width > min_sensible_dimension &&
440 recent.gui_geometry_main_width > min_sensible_dimension) {
441 shadow_main.resize(recent.gui_geometry_main_width, recent.gui_geometry_main_height);
444 // Let Qt move and resize our window if needed (e.g. if it's offscreen)
445 QByteArray geom = shadow_main.saveGeometry();
447 if (strlen (get_conn_cfilter()) < 1) {
448 QPropertyAnimation *pos_anim = new QPropertyAnimation(this, "pos");
449 QPropertyAnimation *size_anim = new QPropertyAnimation(this, "size");
451 shadow_main.restoreGeometry(geom);
453 pos_anim->setDuration(geom_animation_duration);
454 pos_anim->setStartValue(pos());
455 pos_anim->setEndValue(shadow_main.pos());
456 size_anim->setDuration(geom_animation_duration);
457 size_anim->setStartValue(size());
458 size_anim->setEndValue(shadow_main.size());
460 pos_anim->start(QAbstractAnimation::DeleteWhenStopped);
461 size_anim->start(QAbstractAnimation::DeleteWhenStopped);
463 restoreGeometry(geom);
467 if (prefs.gui_geometry_save_maximized && recent.gui_geometry_main_maximized) {
468 setWindowState(Qt::WindowMaximized);
473 void MainWindow::saveWindowGeometry()
475 if (prefs.gui_geometry_save_position) {
476 recent.gui_geometry_main_x = pos().x();
477 recent.gui_geometry_main_y = pos().y();
480 if (prefs.gui_geometry_save_size) {
481 recent.gui_geometry_main_width = size().width();
482 recent.gui_geometry_main_height = size().height();
485 if (prefs.gui_geometry_save_maximized) {
486 // On OS X this is false when it shouldn't be
487 recent.gui_geometry_main_maximized = isMaximized();
491 QWidget* MainWindow::getLayoutWidget(layout_pane_content_e type) {
493 case layout_pane_content_none:
495 case layout_pane_content_plist:
497 case layout_pane_content_pdetails:
499 case layout_pane_content_pbytes:
500 return byte_view_tab_;
502 g_assert_not_reached();
507 void MainWindow::mergeCaptureFile()
509 QString file_name = "";
510 QString display_filter = "";
511 dfilter_t *rfcode = NULL;
517 if (prefs.gui_ask_unsaved) {
518 if (cf_has_unsaved_data(cap_file_)) {
519 QMessageBox msg_dialog;
520 gchar *display_basename;
523 msg_dialog.setIcon(QMessageBox::Question);
524 /* This file has unsaved data; ask the user whether to save
526 if (cap_file_->is_tempfile) {
527 msg_dialog.setText(tr("Save packets before merging?"));
528 msg_dialog.setInformativeText(tr("A temporary capture file can't be merged."));
531 * Format the message.
533 display_basename = g_filename_display_basename(cap_file_->filename);
534 msg_dialog.setText(QString(tr("Save changes in \"%1\" before merging?")).arg(display_basename));
535 g_free(display_basename);
536 msg_dialog.setInformativeText(tr("Changes must be saved before the files can be merged."));
539 msg_dialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
540 msg_dialog.setDefaultButton(QMessageBox::Save);
542 response = msg_dialog.exec();
546 case QMessageBox::Save:
547 /* Save the file but don't close it */
548 saveCaptureFile(cap_file_, FALSE);
551 case QMessageBox::Cancel:
553 /* Don't do the merge. */
560 CaptureFileDialog merge_dlg(this, cap_file_, display_filter);
562 cf_status_t merge_status;
563 char *in_filenames[2];
566 switch (prefs.gui_fileopen_style) {
568 case FO_STYLE_LAST_OPENED:
569 /* The user has specified that we should start out in the last directory
570 we looked in. If we've already opened a file, use its containing
571 directory, if we could determine it, as the directory, otherwise
572 use the "last opened" directory saved in the preferences file if
574 /* This is now the default behaviour in file_selection_new() */
577 case FO_STYLE_SPECIFIED:
578 /* The user has specified that we should always start out in a
579 specified directory; if they've specified that directory,
580 start out by showing the files in that dir. */
581 if (prefs.gui_fileopen_dir[0] != '\0')
582 merge_dlg.setDirectory(prefs.gui_fileopen_dir);
586 if (merge_dlg.merge(file_name)) {
587 if (dfilter_compile(display_filter.toUtf8().constData(), &rfcode)) {
588 cf_set_rfcode(cap_file_, rfcode);
590 /* Not valid. Tell the user, and go back and run the file
591 selection box again once they dismiss the alert. */
592 //bad_dfilter_alert_box(top_level, display_filter->str);
593 QMessageBox::warning(this, tr("Invalid Display Filter"),
594 QString(tr("The filter expression %1 isn't a valid display filter. (%2).").arg(display_filter, dfilter_error_msg)),
602 file_type = cap_file_->cd_t;
604 /* Try to merge or append the two files */
606 if (merge_dlg.mergeType() == 0) {
607 /* chronological order */
608 in_filenames[0] = cap_file_->filename;
609 in_filenames[1] = file_name.toUtf8().data();
610 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
611 } else if (merge_dlg.mergeType() <= 0) {
613 in_filenames[0] = file_name.toUtf8().data();
614 in_filenames[1] = cap_file_->filename;
615 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE);
618 in_filenames[0] = cap_file_->filename;
619 in_filenames[1] = file_name.toUtf8().data();
620 merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE);
623 if (merge_status != CF_OK) {
625 dfilter_free(rfcode);
632 /* Try to open the merged capture file. */
634 if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
635 /* We couldn't open it; fail. */
638 dfilter_free(rfcode);
643 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
644 it closed the previous capture file, and thus destroyed any
645 previous read filter attached to "cf"). */
646 cfile.rfcode = rfcode;
648 switch (cf_read(&cfile, FALSE)) {
652 /* Just because we got an error, that doesn't mean we were unable
653 to read any of the file; we handle what we could get from the
657 case CF_READ_ABORTED:
658 /* The user bailed out of re-reading the capture file; the
659 capture file has been closed - just free the capture file name
660 string and return (without changing the last containing
666 /* Save the name of the containing directory specified in the path name,
667 if any; we can write over cf_merged_name, which is a good thing, given that
668 "get_dirname()" does write over its argument. */
669 wsApp->setLastOpenDir(get_dirname(tmpname));
671 df_combo_box_->setEditText(display_filter);
672 main_ui_->statusBar->showExpert();
678 void MainWindow::importCaptureFile() {
679 ImportTextDialog import_dlg;
681 if (!testCaptureFileClose(FALSE, *new QString(tr(" before importing a new capture"))))
686 if (import_dlg.result() != QDialog::Accepted) {
687 main_ui_->mainStack->setCurrentWidget(main_welcome_);
691 openCaptureFile(import_dlg.capfileName());
694 void MainWindow::saveCaptureFile(capture_file *cf, bool stay_closed) {
696 gboolean discard_comments;
698 if (cf->is_tempfile) {
699 /* This is a temporary capture file, so saving it means saving
700 it to a permanent file. Prompt the user for a location
701 to which to save it. Don't require that the file format
702 support comments - if it's a temporary capture file, it's
703 probably pcap-ng, which supports comments and, if it's
704 not pcap-ng, let the user decide what they want to do
705 if they've added comments. */
706 saveAsCaptureFile(cf, FALSE, stay_closed);
708 if (cf->unsaved_changes) {
709 cf_write_status_t status;
711 /* This is not a temporary capture file, but it has unsaved
712 changes, so saving it means doing a "safe save" on top
713 of the existing file, in the same format - no UI needed
714 unless the file has comments and the file's format doesn't
717 If the file has comments, does the file's format support them?
718 If not, ask the user whether they want to discard the comments
719 or choose a different format. */
720 switch (CaptureFileDialog::checkSaveAsWithComments(this, cf, cf->cd_t)) {
723 /* The file can be saved in the specified format as is;
724 just drive on and save in the format they selected. */
725 discard_comments = FALSE;
728 case SAVE_WITHOUT_COMMENTS:
729 /* The file can't be saved in the specified format as is,
730 but it can be saved without the comments, and the user
731 said "OK, discard the comments", so save it in the
732 format they specified without the comments. */
733 discard_comments = TRUE;
736 case SAVE_IN_ANOTHER_FORMAT:
737 /* There are file formats in which we can save this that
738 support comments, and the user said not to delete the
739 comments. Do a "Save As" so the user can select
740 one of those formats and choose a file name. */
741 saveAsCaptureFile(cf, TRUE, stay_closed);
745 /* The user said "forget it". Just return. */
749 /* Squelch warnings that discard_comments is being used
751 g_assert_not_reached();
755 /* XXX - cf->filename might get freed out from under us, because
756 the code path through which cf_save_packets() goes currently
757 closes the current file and then opens and reloads the saved file,
758 so make a copy and free it later. */
759 file_name = cf->filename;
760 status = cf_save_packets(cf, file_name.toUtf8().constData(), cf->cd_t, cf->iscompressed,
761 discard_comments, stay_closed);
765 /* The save succeeded; we're done.
766 If we discarded comments, redraw the packet list to reflect
767 any packets that no longer have comments. */
768 if (discard_comments)
769 packet_list_queue_draw();
771 cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes
772 updateForUnsavedChanges(); // we update the title bar to remove the *
777 XXX - OK, what do we do now? Let them try a
778 "Save As", in case they want to try to save to a
779 different directory r file system? */
782 case CF_WRITE_ABORTED:
783 /* The write was aborted; just drive on. */
787 /* Otherwise just do nothing. */
791 void MainWindow::saveAsCaptureFile(capture_file *cf, bool must_support_comments, bool stay_closed) {
792 QString file_name = "";
795 cf_write_status_t status;
797 gboolean discard_comments = FALSE;
804 CaptureFileDialog save_as_dlg(this, cf);
806 switch (prefs.gui_fileopen_style) {
808 case FO_STYLE_LAST_OPENED:
809 /* The user has specified that we should start out in the last directory
810 we looked in. If we've already opened a file, use its containing
811 directory, if we could determine it, as the directory, otherwise
812 use the "last opened" directory saved in the preferences file if
814 /* This is now the default behaviour in file_selection_new() */
817 case FO_STYLE_SPECIFIED:
818 /* The user has specified that we should always start out in a
819 specified directory; if they've specified that directory,
820 start out by showing the files in that dir. */
821 if (prefs.gui_fileopen_dir[0] != '\0')
822 save_as_dlg.setDirectory(prefs.gui_fileopen_dir);
826 /* If the file has comments, does the format the user selected
827 support them? If not, ask the user whether they want to
828 discard the comments or choose a different format. */
829 switch(save_as_dlg.saveAs(file_name, must_support_comments)) {
832 /* The file can be saved in the specified format as is;
833 just drive on and save in the format they selected. */
834 discard_comments = FALSE;
837 case SAVE_WITHOUT_COMMENTS:
838 /* The file can't be saved in the specified format as is,
839 but it can be saved without the comments, and the user
840 said "OK, discard the comments", so save it in the
841 format they specified without the comments. */
842 discard_comments = TRUE;
845 case SAVE_IN_ANOTHER_FORMAT:
846 /* There are file formats in which we can save this that
847 support comments, and the user said not to delete the
848 comments. The combo box of file formats has had the
849 formats that don't support comments trimmed from it,
850 so run the dialog again, to let the user decide
851 whether to save in one of those formats or give up. */
852 discard_comments = FALSE;
853 must_support_comments = TRUE;
857 /* The user said "forget it". Just get rid of the dialog box
861 file_type = save_as_dlg.selectedFileType();
862 compressed = save_as_dlg.isCompressed();
864 fileAddExtension(file_name, file_type, compressed);
867 // /* If the file exists and it's user-immutable or not writable,
868 // ask the user whether they want to override that. */
869 // if (!file_target_unwritable_ui(top_level, file_name.toUtf8().constData())) {
870 // /* They don't. Let them try another file name or cancel. */
875 /* Attempt to save the file */
876 status = cf_save_packets(cf, file_name.toUtf8().constData(), file_type, compressed,
877 discard_comments, stay_closed);
881 /* The save succeeded; we're done. */
882 /* Save the directory name for future file dialogs. */
883 dirname = get_dirname(file_name.toUtf8().data()); /* Overwrites cf_name */
884 set_last_open_dir(dirname);
885 /* If we discarded comments, redraw the packet list to reflect
886 any packets that no longer have comments. */
887 if (discard_comments)
888 packet_list_queue_draw();
890 cf->unsaved_changes = false; //we just saved so we signal that we have no unsaved changes
891 updateForUnsavedChanges(); // we update the title bar to remove the *
895 /* The save failed; let the user try again. */
898 case CF_WRITE_ABORTED:
899 /* The user aborted the save; just return. */
906 void MainWindow::exportSelectedPackets() {
907 QString file_name = "";
910 packet_range_t range;
911 cf_write_status_t status;
913 gboolean discard_comments = FALSE;
918 /* Init the packet range */
919 packet_range_init(&range, cap_file_);
920 range.process_filtered = TRUE;
921 range.include_dependents = TRUE;
924 CaptureFileDialog esp_dlg(this, cap_file_);
926 switch (prefs.gui_fileopen_style) {
928 case FO_STYLE_LAST_OPENED:
929 /* The user has specified that we should start out in the last directory
930 we looked in. If we've already opened a file, use its containing
931 directory, if we could determine it, as the directory, otherwise
932 use the "last opened" directory saved in the preferences file if
934 /* This is now the default behaviour in file_selection_new() */
937 case FO_STYLE_SPECIFIED:
938 /* The user has specified that we should always start out in a
939 specified directory; if they've specified that directory,
940 start out by showing the files in that dir. */
941 if (prefs.gui_fileopen_dir[0] != '\0')
942 esp_dlg.setDirectory(prefs.gui_fileopen_dir);
946 /* If the file has comments, does the format the user selected
947 support them? If not, ask the user whether they want to
948 discard the comments or choose a different format. */
949 switch(esp_dlg.exportSelectedPackets(file_name, &range)) {
952 /* The file can be saved in the specified format as is;
953 just drive on and save in the format they selected. */
954 discard_comments = FALSE;
957 case SAVE_WITHOUT_COMMENTS:
958 /* The file can't be saved in the specified format as is,
959 but it can be saved without the comments, and the user
960 said "OK, discard the comments", so save it in the
961 format they specified without the comments. */
962 discard_comments = TRUE;
965 case SAVE_IN_ANOTHER_FORMAT:
966 /* There are file formats in which we can save this that
967 support comments, and the user said not to delete the
968 comments. The combo box of file formats has had the
969 formats that don't support comments trimmed from it,
970 so run the dialog again, to let the user decide
971 whether to save in one of those formats or give up. */
972 discard_comments = FALSE;
976 /* The user said "forget it". Just get rid of the dialog box
982 * Check that we're not going to save on top of the current
984 * We do it here so we catch all cases ...
985 * Unfortunately, the file requester gives us an absolute file
986 * name and the read file name may be relative (if supplied on
987 * the command line). From Joerg Mayer.
989 if (files_identical(cap_file_->filename, file_name.toUtf8().constData())) {
991 gchar *display_basename = g_filename_display_basename(file_name.toUtf8().constData());
993 msg_box.setIcon(QMessageBox::Critical);
994 msg_box.setText(QString(tr("Unable to export to \"%1\".").arg(display_basename)));
995 msg_box.setInformativeText(tr("You cannot export packets to the current capture file."));
996 msg_box.setStandardButtons(QMessageBox::Ok);
997 msg_box.setDefaultButton(QMessageBox::Ok);
999 g_free(display_basename);
1003 file_type = esp_dlg.selectedFileType();
1004 compressed = esp_dlg.isCompressed();
1005 fileAddExtension(file_name, file_type, compressed);
1008 // /* If the file exists and it's user-immutable or not writable,
1009 // ask the user whether they want to override that. */
1010 // if (!file_target_unwritable_ui(top_level, file_name.toUtf8().constData())) {
1011 // /* They don't. Let them try another file name or cancel. */
1016 /* Attempt to save the file */
1017 status = cf_export_specified_packets(cap_file_, file_name.toUtf8().constData(), &range, file_type, compressed);
1021 /* The save succeeded; we're done. */
1022 /* Save the directory name for future file dialogs. */
1023 dirname = get_dirname(file_name.toUtf8().data()); /* Overwrites cf_name */
1024 set_last_open_dir(dirname);
1025 /* If we discarded comments, redraw the packet list to reflect
1026 any packets that no longer have comments. */
1027 if (discard_comments)
1028 packet_list_queue_draw();
1031 case CF_WRITE_ERROR:
1032 /* The save failed; let the user try again. */
1035 case CF_WRITE_ABORTED:
1036 /* The user aborted the save; just return. */
1043 void MainWindow::exportDissections(export_type_e export_type) {
1044 ExportDissectionDialog ed_dlg(this, cap_file_, export_type);
1045 packet_range_t range;
1050 /* Init the packet range */
1051 packet_range_init(&range, cap_file_);
1052 range.process_filtered = TRUE;
1053 range.include_dependents = TRUE;
1058 void MainWindow::fileAddExtension(QString &file_name, int file_type, bool compressed) {
1059 QString file_name_lower;
1060 QString file_suffix;
1061 GSList *extensions_list;
1062 gboolean add_extension;
1065 * Append the default file extension if there's none given by
1066 * the user or if they gave one that's not one of the valid
1067 * extensions for the file type.
1069 file_name_lower = file_name.toLower();
1070 extensions_list = wtap_get_file_extensions_list(file_type, FALSE);
1071 if (extensions_list != NULL) {
1074 /* We have one or more extensions for this file type.
1075 Start out assuming we need to add the default one. */
1076 add_extension = TRUE;
1078 /* OK, see if the file has one of those extensions. */
1079 for (extension = extensions_list; extension != NULL;
1080 extension = g_slist_next(extension)) {
1081 file_suffix += tr(".") + (char *)extension->data;
1082 if (file_name_lower.endsWith(file_suffix)) {
1084 * The file name has one of the extensions for
1087 add_extension = FALSE;
1090 file_suffix += ".gz";
1091 if (file_name_lower.endsWith(file_suffix)) {
1093 * The file name has one of the extensions for
1096 add_extension = FALSE;
1101 /* We have no extensions for this file type. Don't add one. */
1102 add_extension = FALSE;
1104 if (add_extension) {
1105 if (wtap_default_file_extension(file_type) != NULL) {
1106 file_name += tr(".") + wtap_default_file_extension(file_type);
1114 bool MainWindow::testCaptureFileClose(bool from_quit, QString &before_what) {
1115 bool capture_in_progress = FALSE;
1117 if (!cap_file_ || cap_file_->state == FILE_CLOSED)
1118 return true; /* Already closed, nothing to do */
1121 if (cap_file_->state == FILE_READ_IN_PROGRESS) {
1122 /* This is true if we're reading a capture file *or* if we're doing
1123 a live capture. If we're reading a capture file, the main loop
1124 is busy reading packets, and only accepting input from the
1125 progress dialog, so we can't get here, so this means we're
1127 capture_in_progress = TRUE;
1131 if (prefs.gui_ask_unsaved) {
1132 if (cf_has_unsaved_data(cap_file_) || capture_in_progress) {
1133 QMessageBox msg_dialog;
1135 QPushButton *saveButton;
1136 QPushButton *discardButton;
1138 msg_dialog.setIcon(QMessageBox::Question);
1140 /* This file has unsaved data or there's a capture in
1141 progress; ask the user whether to save the data. */
1142 if (cap_file_->is_tempfile) {
1144 msg_dialog.setText(tr("You have unsaved packets"));
1145 msg_dialog.setInformativeText(tr("They will be lost if you don't save them."));
1147 if (capture_in_progress) {
1148 question.append(tr("Do you want to stop the capture and save the captured packets"));
1150 question.append(tr("Do you want to save the captured packets"));
1152 question.append(before_what).append(tr("?"));
1153 msg_dialog.setInformativeText(question);
1158 * Format the message.
1160 if (capture_in_progress) {
1161 question.append(tr("Do you want to stop the capture and save the captured packets"));
1162 question.append(before_what).append(tr("?"));
1163 msg_dialog.setInformativeText(tr("Your captured packets will be lost if you don't save them."));
1165 gchar *display_basename = g_filename_display_basename(cap_file_->filename);
1166 question.append(QString(tr("Do you want to save the changes you've made to the capture file \"%1\"%2?"))
1167 .arg(display_basename)
1170 g_free(display_basename);
1171 msg_dialog.setInformativeText(tr("Your changes will be lost if you don't save them."));
1175 // XXX Text comes from ui/gtk/stock_icons.[ch]
1176 // Note that the button roles differ from the GTK+ version.
1177 // Cancel = RejectRole
1178 // Save = AcceptRole
1179 // Don't Save = DestructiveRole
1180 msg_dialog.addButton(QMessageBox::Cancel);
1182 if (capture_in_progress) {
1183 saveButton = msg_dialog.addButton(tr("Stop and Save"), QMessageBox::AcceptRole);
1185 saveButton = msg_dialog.addButton(QMessageBox::Save);
1187 msg_dialog.setDefaultButton(saveButton);
1190 if (cap_file_->state == FILE_READ_IN_PROGRESS) {
1191 discardButton = msg_dialog.addButton(tr("Stop and Quit without Saving"),
1192 QMessageBox::DestructiveRole);
1194 discardButton = msg_dialog.addButton(tr("Quit without Saving"),
1195 QMessageBox::DestructiveRole);
1198 if (capture_in_progress) {
1199 discardButton = msg_dialog.addButton(tr("Stop and Continue without Saving"),
1200 QMessageBox::DestructiveRole);
1202 discardButton = msg_dialog.addButton(QMessageBox::Discard);
1207 /* According to the Qt doc:
1208 * when using QMessageBox with custom buttons, exec() function returns an opaque value.
1210 * Therefore we should use clickedButton() to determine which button was clicked. */
1212 if(msg_dialog.clickedButton() == saveButton)
1215 /* If there's a capture in progress, we have to stop the capture
1216 and then do the save. */
1217 if (capture_in_progress)
1220 /* Save the file and close it */
1221 saveCaptureFile(cap_file_, TRUE);
1223 else if(msg_dialog.clickedButton() == discardButton)
1227 * If there's a capture in progress; we have to stop the capture
1228 * and then do the close.
1230 if (capture_in_progress)
1233 /* Just close the file, discarding changes */
1234 cf_close(cap_file_);
1237 else //cancelButton or some other unspecified button
1243 /* Unchanged file, just close it */
1244 cf_close(cap_file_);
1247 /* User asked not to be bothered by those prompts, just close it.
1248 XXX - should that apply only to saving temporary files? */
1250 /* If there's a capture in progress, we have to stop the capture
1251 and then do the close. */
1252 if (capture_in_progress)
1255 cf_close(cap_file_);
1258 return true; /* File closed */
1261 void MainWindow::captureStop() {
1264 while(cap_file_ && cap_file_->state == FILE_READ_IN_PROGRESS) {
1265 WiresharkApplication::processEvents();
1270 void MainWindow::setTitlebarForCaptureFile()
1272 if (cap_file_ && cap_file_->filename) {
1274 // Qt *REALLY* doesn't like windows that sometimes have a
1275 // title set with setWindowTitle() and other times have a
1276 // file path set; apparently, once you've set the title
1277 // with setWindowTitle(), it sticks, and setWindowFilePath()
1278 // has no effect. It appears to can clear the title with
1279 // setWindowTitle(NULL), but that clears the actual title in
1280 // the title bar, and setWindowFilePath() then, I guess, sees
1281 // that there's already a file path, and does nothing, leaving
1282 // the title bar empty. So you then have to clear the file path
1283 // with setWindowFilePath(NULL), and then set it.
1285 // Maybe there's a #include "you're holding it wrong" here.
1286 // However, I really don't want to hear from people who think
1287 // that a window can never be associated with something other
1288 // than a user file at time T1 and with a user file at time T2,
1289 // given that, in Wireshark, a window can be associated with a
1290 // live capture at time T1 and then, after you've saved the live
1291 // capture to a user file, associated with a user file at time T2.
1293 if (cap_file_->is_tempfile) {
1295 // For a temporary file, put the source of the data
1296 // in the window title, not whatever random pile
1297 // of characters is the last component of the path
1300 // XXX - on non-Mac platforms, put in the application
1304 setWindowFilePath(NULL);
1305 window_name = g_strdup_printf("Capturing from %s[*]", cf_get_tempfile_source(cap_file_)); //TODO : Fix Translate
1306 setWindowTitle(window_name);
1307 g_free(window_name);
1310 // For a user file, set the full path; that way,
1311 // for OS X, it'll set the "proxy icon". Qt
1312 // handles extracting the last component.
1314 // Sadly, some UN*Xes don't necessarily use UTF-8
1315 // for their file names, so we have to map the
1316 // file path to UTF-8. If that fails, we're somewhat
1319 char *utf8_filename = g_filename_to_utf8(cap_file_->filename,
1324 if (utf8_filename == NULL) {
1325 // So what the heck else can we do here?
1326 setWindowTitle(tr("(File name can't be mapped to UTF-8)"));
1328 setWindowTitle(NULL);
1329 setWindowFilePath(NULL);
1330 setWindowFilePath(utf8_filename);
1331 g_free(utf8_filename);
1334 setWindowModified(cf_has_unsaved_data(cap_file_));
1336 /* We have no capture file. */
1337 setWindowFilePath(NULL);
1338 setWindowTitle(tr("The Wireshark Network Analyzer"));
1342 void MainWindow::setTitlebarForSelectedTreeRow()
1344 setWindowTitle(tr("The Wireshark Network Analyzer"));
1348 void MainWindow::setTitlebarForCaptureInProgress()
1352 setWindowFilePath(NULL);
1354 window_name = g_strdup_printf("Capturing from %s", cf_get_tempfile_source(cap_file_)); //TODO : Fix Translate
1355 setWindowTitle(window_name);
1356 g_free(window_name);
1358 /* We have no capture in progress. */
1359 setWindowTitle(tr("The Wireshark Network Analyzer"));
1365 void MainWindow::setMenusForFollowStream()
1370 if (!cap_file_->edt)
1373 main_ui_->actionAnalyzeFollowTCPStream->setEnabled(false);
1374 main_ui_->actionAnalyzeFollowUDPStream->setEnabled(false);
1375 main_ui_->actionAnalyzeFollowSSLStream->setEnabled(false);
1377 if (cap_file_->edt->pi.ipproto == IP_PROTO_TCP)
1379 main_ui_->actionAnalyzeFollowTCPStream->setEnabled(true);
1382 if (cap_file_->edt->pi.ipproto == IP_PROTO_UDP)
1384 main_ui_->actionAnalyzeFollowUDPStream->setEnabled(true);
1387 if ( epan_dissect_packet_contains_field(cap_file_->edt, "ssl") )
1389 main_ui_->actionAnalyzeFollowSSLStream->setEnabled(true);
1393 /* Enable or disable menu items based on whether you have a capture file
1394 you've finished reading and, if you have one, whether it's been saved
1395 and whether it could be saved except by copying the raw packet data. */
1396 void MainWindow::setMenusForCaptureFile(bool force_disable)
1398 if (force_disable || cap_file_ == NULL || cap_file_->state == FILE_READ_IN_PROGRESS) {
1399 /* We have no capture file or we're currently reading a file */
1400 main_ui_->actionFileMerge->setEnabled(false);
1401 main_ui_->actionFileClose->setEnabled(false);
1402 main_ui_->actionFileSave->setEnabled(false);
1403 main_ui_->actionFileSaveAs->setEnabled(false);
1404 main_ui_->actionSummary->setEnabled(false);
1405 main_ui_->actionFileExportPackets->setEnabled(false);
1406 main_ui_->menuFileExportPacketDissections->setEnabled(false);
1407 main_ui_->actionFileExportPacketBytes->setEnabled(false);
1408 main_ui_->actionFileExportSSLSessionKeys->setEnabled(false);
1409 main_ui_->menuFileExportObjects->setEnabled(false);
1410 main_ui_->actionViewReload->setEnabled(false);
1412 main_ui_->actionFileMerge->setEnabled(cf_can_write_with_wiretap(cap_file_));
1414 main_ui_->actionFileClose->setEnabled(true);
1415 main_ui_->actionFileSave->setEnabled(cf_can_save(cap_file_));
1416 main_ui_->actionFileSaveAs->setEnabled(cf_can_save_as(cap_file_));
1417 main_ui_->actionSummary->setEnabled(true);
1419 * "Export Specified Packets..." should be available only if
1420 * we can write the file out in at least one format.
1422 main_ui_->actionFileExportPackets->setEnabled(cf_can_write_with_wiretap(cap_file_));
1423 main_ui_->menuFileExportPacketDissections->setEnabled(true);
1424 main_ui_->actionFileExportPacketBytes->setEnabled(true);
1425 main_ui_->actionFileExportSSLSessionKeys->setEnabled(true);
1426 main_ui_->menuFileExportObjects->setEnabled(true);
1427 main_ui_->actionViewReload->setEnabled(true);
1431 void MainWindow::setMenusForCaptureInProgress(bool capture_in_progress) {
1432 /* Either a capture was started or stopped; in either case, it's not
1433 in the process of stopping, so allow quitting. */
1435 main_ui_->actionFileOpen->setEnabled(!capture_in_progress);
1436 main_ui_->menuOpenRecentCaptureFile->setEnabled(!capture_in_progress);
1437 main_ui_->menuFileExportPacketDissections->setEnabled(capture_in_progress);
1438 main_ui_->actionFileExportPacketBytes->setEnabled(capture_in_progress);
1439 main_ui_->actionFileExportSSLSessionKeys->setEnabled(capture_in_progress);
1440 main_ui_->menuFileExportObjects->setEnabled(capture_in_progress);
1441 main_ui_->menuFileSet->setEnabled(!capture_in_progress);
1442 main_ui_->actionFileQuit->setEnabled(true);
1444 main_ui_->actionSummary->setEnabled(capture_in_progress);
1446 qDebug() << "FIX: packet list heading menu sensitivity";
1447 // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortAscending",
1448 // !capture_in_progress);
1449 // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortDescending",
1450 // !capture_in_progress);
1451 // set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/NoSorting",
1452 // !capture_in_progress);
1455 main_ui_->actionCaptureOptions->setEnabled(!capture_in_progress);
1456 main_ui_->actionStartCapture->setEnabled(!capture_in_progress);
1457 main_ui_->actionStartCapture->setChecked(capture_in_progress);
1458 main_ui_->actionStopCapture->setEnabled(capture_in_progress);
1459 main_ui_->actionCaptureRestart->setEnabled(capture_in_progress);
1460 #endif /* HAVE_LIBPCAP */
1464 void MainWindow::setMenusForCaptureStopping() {
1465 main_ui_->actionFileQuit->setEnabled(false);
1466 main_ui_->actionSummary->setEnabled(false);
1468 main_ui_->actionStartCapture->setChecked(false);
1469 main_ui_->actionStopCapture->setEnabled(false);
1470 main_ui_->actionCaptureRestart->setEnabled(false);
1471 #endif /* HAVE_LIBPCAP */
1474 void MainWindow::setForCapturedPackets(bool have_captured_packets)
1476 main_ui_->actionFilePrint->setEnabled(have_captured_packets);
1478 // set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/Print",
1479 // have_captured_packets);
1481 main_ui_->actionEditFindPacket->setEnabled(have_captured_packets);
1482 main_ui_->actionEditFindNext->setEnabled(have_captured_packets);
1483 main_ui_->actionEditFindPrevious->setEnabled(have_captured_packets);
1484 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/ZoomIn",
1485 // have_captured_packets);
1486 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/ZoomOut",
1487 // have_captured_packets);
1488 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/NormalSize",
1489 // have_captured_packets);
1491 main_ui_->actionGoGoToPacket->setEnabled(have_captured_packets);
1492 main_ui_->actionGoPreviousPacket->setEnabled(have_captured_packets);
1493 main_ui_->actionGoNextPacket->setEnabled(have_captured_packets);
1494 main_ui_->actionGoFirstPacket->setEnabled(have_captured_packets);
1495 main_ui_->actionGoLastPacket->setEnabled(have_captured_packets);
1497 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/GoMenu/PreviousPacketInConversation",
1498 // have_captured_packets);
1499 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/GoMenu/NextPacketInConversation",
1500 // have_captured_packets);
1501 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/Summary",
1502 // have_captured_packets);
1503 // set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/ProtocolHierarchy",
1504 // have_captured_packets);
1507 void MainWindow::setMenusForFileSet(bool enable_list_files) {
1508 bool enable_next = fileset_get_next() != NULL && enable_list_files;
1509 bool enable_prev = fileset_get_previous() != NULL && enable_list_files;
1511 main_ui_->actionFileSetListFiles->setEnabled(enable_list_files);
1512 main_ui_->actionFileSetNextFile->setEnabled(enable_next);
1513 main_ui_->actionFileSetPreviousFile->setEnabled(enable_prev);
1516 void MainWindow::updateForUnsavedChanges() {
1517 setTitlebarForCaptureFile();
1518 setMenusForCaptureFile();
1519 // set_toolbar_for_capture_file(cf);
1523 /* Update main window items based on whether there's a capture in progress. */
1524 void MainWindow::setForCaptureInProgress(gboolean capture_in_progress)
1526 setMenusForCaptureInProgress(capture_in_progress);
1528 //#ifdef HAVE_LIBPCAP
1529 // set_toolbar_for_capture_in_progress(capture_in_progress);
1531 // set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
1541 * indent-tabs-mode: nil
1544 * ex: set shiftwidth=4 tabstop=8 expandtab:
1545 * :indentSize=4:tabSize=8:noTabs=true: