Rename the search type menu items to more accurately reflect what we're
[metze/wireshark/wip.git] / ui / qt / main_window.cpp
1 /* main_window.cpp
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
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.
13  *
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.
18  *
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.
22  */
23
24 #include "main_window.h"
25 #include "ui_main_window.h"
26
27 #include "globals.h"
28
29 #include <epan/filesystem.h>
30 #include <epan/prefs.h>
31
32 //#include <wiretap/wtap.h>
33
34 #ifdef HAVE_LIBPCAP
35 #include "capture.h"
36 #include "capture-pcap-util.h"
37 #include "capture_ui_utils.h"
38 #endif
39
40 #include "ui/alert_box.h"
41 #include "ui/main_statusbar.h"
42 #include "ui/capture_globals.h"
43
44 #include "wireshark_application.h"
45 #include "proto_tree.h"
46 #include "byte_view_tab.h"
47 #include "display_filter_edit.h"
48 #include "import_text_dialog.h"
49 #include "export_dissection_dialog.h"
50
51 #include "qt_ui_utils.h"
52
53 #include <QTreeWidget>
54 #include <QTabWidget>
55 #include <QAction>
56 #include <QToolButton>
57 #include <QKeyEvent>
58 #include <QMetaObject>
59 #include <QMessageBox>
60
61 //menu_recent_file_write_all
62
63 // If we ever add support for multiple windows this will need to be replaced.
64 static MainWindow *gbl_cur_main_window = NULL;
65
66 void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
67 {
68     gbl_cur_main_window->setPipeInputHandler(source, user_data, child_process, input_cb);
69 }
70
71 MainWindow::MainWindow(QWidget *parent) :
72     QMainWindow(parent),
73     main_ui_(new Ui::MainWindow),
74     df_combo_box_(new DisplayFilterCombo()),
75     cap_file_(NULL),
76     previous_focus_(NULL),
77     capture_stopping_(false),
78 #ifdef _WIN32
79     pipe_timer_(NULL)
80 #else
81     pipe_notifier_(NULL)
82 #endif
83 {
84     gbl_cur_main_window = this;
85     main_ui_->setupUi(this);
86     setMenusForCaptureFile();
87     setForCapturedPackets(false);
88     setMenusForSelectedTreeRow();
89     setForCaptureInProgress(false);
90     setMenusForFileSet(false);
91     interfaceSelectionChanged();
92
93     connect(wsApp, SIGNAL(updateRecentItemStatus(const QString &, qint64, bool)), this, SLOT(updateRecentFiles()));
94     updateRecentFiles();
95
96     const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
97     connect(df_edit, SIGNAL(pushFilterSyntaxStatus(QString&)), main_ui_->statusBar, SLOT(pushFilterStatus(QString&)));
98     connect(df_edit, SIGNAL(popFilterSyntaxStatus()), main_ui_->statusBar, SLOT(popFilterStatus()));
99     connect(df_edit, SIGNAL(pushFilterSyntaxWarning(QString&)), main_ui_->statusBar, SLOT(pushTemporaryStatus(QString&)));
100     connect(df_edit, SIGNAL(filterPackets(QString&,bool)), this, SLOT(filterPackets(QString&,bool)));
101     connect (this, SIGNAL(displayFilterSuccess(bool)), df_edit, SLOT(displayFilterSuccess(bool)));
102
103     // http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
104     // http://qt-project.org/doc/qt-4.8/qstyle.html#StandardPixmap-enum
105     main_ui_->actionFileOpen->setIcon(
106                 QIcon().fromTheme("document-open", style()->standardIcon(QStyle::SP_DirIcon)));
107     // main_ui_->actionFileSave set in main_window.ui
108     main_ui_->actionFileClose->setIcon(
109                 QIcon().fromTheme("process-stop", style()->standardIcon(QStyle::SP_DialogCloseButton)));
110
111     // In Qt4 multiple toolbars and "pretty" are mutually exculsive on OS X. If
112     // unifiedTitleAndToolBarOnMac is enabled everything ends up in the same row.
113     // https://bugreports.qt-project.org/browse/QTBUG-22433
114     // This property is obsolete in Qt5 so this issue may be fixed in that version.
115     main_ui_->displayFilterToolBar->addWidget(df_combo_box_);
116
117     QString subframe_style(
118                 ".QFrame {"
119                 "  background: palette(window);"
120                 "  padding-top: 0.1em;"
121                 "  padding-bottom: 0.1em;"
122                 "  border-bottom: 1px solid palette(shadow);"
123                 "}"
124                 "QLineEdit#goToLineEdit {"
125                 "  max-width: 5em;"
126                 "}"
127                 );
128     main_ui_->goToFrame->hide();
129     // XXX For some reason the cursor is drawn funny with an input mask set
130     // https://bugreports.qt-project.org/browse/QTBUG-7174
131     main_ui_->goToFrame->setStyleSheet(subframe_style);
132
133     main_ui_->searchFrame->hide();
134     main_ui_->searchFrame->setStyleSheet(subframe_style);
135     connect(main_ui_->searchFrame, SIGNAL(pushFilterSyntaxStatus(QString&)),
136             main_ui_->statusBar, SLOT(pushTemporaryStatus(QString&)));
137
138 #if defined(Q_WS_MAC)
139     foreach (QMenu *menu, main_ui_->menuBar->findChildren<QMenu*>()) {
140         foreach (QAction *act, menu->actions()) {
141             act->setIconVisibleInMenu(false);
142         }
143     }
144     main_ui_->goToLineEdit->setAttribute(Qt::WA_MacSmallSize, true);
145     main_ui_->goToGo->setAttribute(Qt::WA_MacSmallSize, true);
146     main_ui_->goToCancel->setAttribute(Qt::WA_MacSmallSize, true);
147 #endif
148
149     packet_splitter_ = new QSplitter(main_ui_->mainStack);
150     packet_splitter_->setObjectName(QString::fromUtf8("splitterV"));
151     packet_splitter_->setOrientation(Qt::Vertical);
152
153     packet_list_ = new PacketList(packet_splitter_);
154
155     proto_tree_ = new ProtoTree(packet_splitter_);
156     proto_tree_->setHeaderHidden(true);
157     proto_tree_->installEventFilter(this);
158
159     ByteViewTab *byte_view_tab = new ByteViewTab(packet_splitter_);
160     byte_view_tab->setTabPosition(QTabWidget::South);
161     byte_view_tab->setDocumentMode(true);
162
163     packet_list_->setProtoTree(proto_tree_);
164     packet_list_->setByteViewTab(byte_view_tab);
165     packet_list_->installEventFilter(this);
166
167     packet_splitter_->addWidget(packet_list_);
168     packet_splitter_->addWidget(proto_tree_);
169     packet_splitter_->addWidget(byte_view_tab);
170
171     main_ui_->mainStack->addWidget(packet_splitter_);
172
173     main_welcome_ = main_ui_->welcomePage;
174
175 #ifdef HAVE_LIBPCAP
176     connect(wsApp, SIGNAL(captureCapturePrepared(capture_options *)),
177             this, SLOT(captureCapturePrepared(capture_options *)));
178     connect(wsApp, SIGNAL(captureCaptureUpdateStarted(capture_options *)),
179             this, SLOT(captureCaptureUpdateStarted(capture_options *)));
180     connect(wsApp, SIGNAL(captureCaptureUpdateFinished(capture_options *)),
181             this, SLOT(captureCaptureUpdateFinished(capture_options *)));
182     connect(wsApp, SIGNAL(captureCaptureFixedStarted(capture_options *)),
183             this, SLOT(captureCaptureFixedStarted(capture_options *)));
184     connect(wsApp, SIGNAL(captureCaptureFixedFinished(capture_options *)),
185             this, SLOT(captureCaptureFixedFinished(capture_options *)));
186     connect(wsApp, SIGNAL(captureCaptureStopping(capture_options *)),
187             this, SLOT(captureCaptureStopping(capture_options *)));
188     connect(wsApp, SIGNAL(captureCaptureFailed(capture_options *)),
189             this, SLOT(captureCaptureFailed(capture_options *)));
190 #endif
191
192     connect(wsApp, SIGNAL(captureFileOpened(const capture_file*)),
193             this, SLOT(captureFileOpened(const capture_file*)));
194     connect(wsApp, SIGNAL(captureFileReadStarted(const capture_file*)),
195             this, SLOT(captureFileReadStarted(const capture_file*)));
196     connect(wsApp, SIGNAL(captureFileReadFinished(const capture_file*)),
197             this, SLOT(captureFileReadFinished(const capture_file*)));
198     connect(wsApp, SIGNAL(captureFileClosing(const capture_file*)),
199             this, SLOT(captureFileClosing(const capture_file*)));
200     connect(wsApp, SIGNAL(captureFileClosed(const capture_file*)),
201             this, SLOT(captureFileClosed(const capture_file*)));
202
203     connect(main_welcome_, SIGNAL(startCapture()),
204             this, SLOT(startCapture()));
205     connect(main_welcome_, SIGNAL(recentFileActivated(QString&)),
206             this, SLOT(openCaptureFile(QString&)));
207
208     connect(this, SIGNAL(setCaptureFile(capture_file*)),
209             main_ui_->searchFrame, SLOT(setCaptureFile(capture_file*)));
210     connect(this, SIGNAL(setCaptureFile(capture_file*)),
211             main_ui_->statusBar, SLOT(setCaptureFile(capture_file*)));
212     connect(this, SIGNAL(setCaptureFile(capture_file*)),
213             packet_list_, SLOT(setCaptureFile(capture_file*)));
214     connect(this, SIGNAL(setCaptureFile(capture_file*)),
215             byte_view_tab, SLOT(setCaptureFile(capture_file*)));
216
217     connect(main_ui_->actionGoNextPacket, SIGNAL(triggered()),
218             packet_list_, SLOT(goNextPacket()));
219     connect(main_ui_->actionGoPreviousPacket, SIGNAL(triggered()),
220             packet_list_, SLOT(goPreviousPacket()));
221     connect(main_ui_->actionGoFirstPacket, SIGNAL(triggered()),
222             packet_list_, SLOT(goFirstPacket()));
223     connect(main_ui_->actionGoLastPacket, SIGNAL(triggered()),
224             packet_list_, SLOT(goLastPacket()));
225
226     connect(main_ui_->actionViewExpandSubtrees, SIGNAL(triggered()),
227             proto_tree_, SLOT(expandSubtrees()));
228     connect(main_ui_->actionViewExpandAll, SIGNAL(triggered()),
229             proto_tree_, SLOT(expandAll()));
230     connect(main_ui_->actionViewCollapseAll, SIGNAL(triggered()),
231             proto_tree_, SLOT(collapseAll()));
232
233     connect(proto_tree_, SIGNAL(protoItemSelected(QString&)),
234             main_ui_->statusBar, SLOT(pushFieldStatus(QString&)));
235
236     connect(proto_tree_, SIGNAL(protoItemSelected(field_info *)),
237             this, SLOT(setMenusForSelectedTreeRow(field_info *)));
238
239     connect(&file_set_dialog_, SIGNAL(fileSetOpenCaptureFile(QString&)),
240             this, SLOT(openCaptureFile(QString&)));
241
242     QTreeWidget *iface_tree = findChild<QTreeWidget *>("interfaceTree");
243     if (iface_tree) {
244         connect(iface_tree, SIGNAL(itemSelectionChanged()),
245                 this, SLOT(interfaceSelectionChanged()));
246     }
247     main_ui_->mainStack->setCurrentWidget(main_welcome_);
248 }
249
250 MainWindow::~MainWindow()
251 {
252     delete main_ui_;
253 }
254
255 #include <QDebug>
256 void MainWindow::setPipeInputHandler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
257 {
258     pipe_source_        = source;
259     pipe_child_process_ = child_process;
260     pipe_user_data_     = user_data;
261     pipe_input_cb_      = input_cb;
262
263 #ifdef _WIN32
264     /* Tricky to use pipes in win9x, as no concept of wait.  NT can
265        do this but that doesn't cover all win32 platforms.  GTK can do
266        this but doesn't seem to work over processes.  Attempt to do
267        something similar here, start a timer and check for data on every
268        timeout. */
269        /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
270
271     if (pipe_timer_) {
272         disconnect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout()));
273         delete pipe_timer_;
274     }
275
276     pipe_timer_ = new QTimer(this);
277     connect(pipe_timer_, SIGNAL(timeout()), this, SLOT(pipeTimeout()));
278     connect(pipe_timer_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed()));
279     pipe_timer_->start(200);
280 #else
281     if (pipe_notifier_) {
282         disconnect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int)));
283         delete pipe_notifier_;
284     }
285
286     pipe_notifier_ = new QSocketNotifier(pipe_source_, QSocketNotifier::Read);
287     // XXX ui/gtk/gui_utils.c sets the encoding. Do we need to do the same?
288     connect(pipe_notifier_, SIGNAL(activated(int)), this, SLOT(pipeActivated(int)));
289     connect(pipe_notifier_, SIGNAL(destroyed()), this, SLOT(pipeNotifierDestroyed()));
290 #endif
291 }
292
293
294 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
295
296     // The user typed some text. Start filling in a filter.
297     // We may need to be more choosy here. We just need to catch events for the packet list,
298     // proto tree, and main welcome widgets.
299     if (event->type() == QEvent::KeyPress) {
300         QKeyEvent *kevt = static_cast<QKeyEvent *>(event);
301         if (kevt->text().length() > 0 && kevt->text()[0].isPrint()) {
302             df_combo_box_->lineEdit()->insert(kevt->text());
303             df_combo_box_->lineEdit()->setFocus();
304             return true;
305         }
306     }
307
308     return QObject::eventFilter(obj, event);
309 }
310
311 void MainWindow::keyPressEvent(QKeyEvent *event) {
312
313     // Explicitly focus on the display filter combo.
314     if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_Slash) {
315         df_combo_box_->setFocus(Qt::ShortcutFocusReason);
316         return;
317     }
318
319     if (wsApp->focusWidget() == main_ui_->goToLineEdit) {
320         if (event->modifiers() == Qt::NoModifier) {
321             if (event->key() == Qt::Key_Escape) {
322                 on_goToCancel_clicked();
323             } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
324                 on_goToGo_clicked();
325             }
326         }
327         return; // goToLineEdit didn't want it and we don't either.
328     }
329
330     // Move up & down the packet list.
331     if (event->key() == Qt::Key_F7) {
332         packet_list_->goPreviousPacket();
333     } else if (event->key() == Qt::Key_F8) {
334         packet_list_->goNextPacket();
335     }
336
337     // Move along, citizen.
338     QMainWindow::keyPressEvent(event);
339 }
340
341 void MainWindow::closeEvent(QCloseEvent *event) {
342    /* If we're in the middle of stopping a capture, don't do anything;
343       the user can try deleting the window after the capture stops. */
344     if (capture_stopping_) {
345         event->ignore();
346     }
347 }
348
349
350 void MainWindow::mergeCaptureFile()
351 {
352     QString file_name = "";
353     QString display_filter = "";
354     dfilter_t *rfcode = NULL;
355     int err;
356
357     if (!cap_file_)
358         return;
359
360     if (prefs.gui_ask_unsaved) {
361         if (cap_file_->is_tempfile || cap_file_->unsaved_changes) {
362             QMessageBox msg_dialog;
363             gchar *display_basename;
364             int response;
365
366             msg_dialog.setIcon(QMessageBox::Question);
367             /* This is a temporary capture file or has unsaved changes; ask the
368                user whether to save the capture. */
369             if (cap_file_->is_tempfile) {
370                 msg_dialog.setText(tr("Save packets before merging?"));
371                 msg_dialog.setInformativeText(tr("A temporary capture file can't be merged."));
372             } else {
373                 /*
374                  * Format the message.
375                  */
376                 display_basename = g_filename_display_basename(cap_file_->filename);
377                 msg_dialog.setText(QString(tr("Save changes in \"%1\" before merging?")).arg(display_basename));
378                 g_free(display_basename);
379                 msg_dialog.setInformativeText(tr("Changes must be saved before the files can be merged."));
380             }
381
382             msg_dialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
383             msg_dialog.setDefaultButton(QMessageBox::Save);
384
385             response = msg_dialog.exec();
386
387             switch (response) {
388
389             case QMessageBox::Save:
390                 /* Save the file but don't close it */
391                 saveCaptureFile(cap_file_, FALSE);
392                 break;
393
394             case QMessageBox::Cancel:
395             default:
396                 /* Don't do the merge. */
397                 return;
398             }
399         }
400     }
401
402     for (;;) {
403         CaptureFileDialog merge_dlg(this, cap_file_, display_filter);
404         int file_type;
405         cf_status_t  merge_status;
406         char        *in_filenames[2];
407         char        *tmpname;
408
409         switch (prefs.gui_fileopen_style) {
410
411         case FO_STYLE_LAST_OPENED:
412             /* The user has specified that we should start out in the last directory
413            we looked in.  If we've already opened a file, use its containing
414            directory, if we could determine it, as the directory, otherwise
415            use the "last opened" directory saved in the preferences file if
416            there was one. */
417             /* This is now the default behaviour in file_selection_new() */
418             break;
419
420         case FO_STYLE_SPECIFIED:
421             /* The user has specified that we should always start out in a
422            specified directory; if they've specified that directory,
423            start out by showing the files in that dir. */
424             if (prefs.gui_fileopen_dir[0] != '\0')
425                 merge_dlg.setDirectory(prefs.gui_fileopen_dir);
426             break;
427         }
428
429         if (merge_dlg.merge(file_name)) {
430             if (dfilter_compile(display_filter.toUtf8().constData(), &rfcode)) {
431                 cf_set_rfcode(cap_file_, rfcode);
432             } else {
433                 /* Not valid.  Tell the user, and go back and run the file
434                    selection box again once they dismiss the alert. */
435                 //bad_dfilter_alert_box(top_level, display_filter->str);
436                 QMessageBox::warning(this, tr("Invalid Display Filter"),
437                                      QString(tr("The filter expression %1 isn't a valid display filter. (%2).").arg(display_filter, dfilter_error_msg)),
438                                      QMessageBox::Ok);
439                 continue;
440             }
441         } else {
442             return;
443         }
444
445         file_type = cap_file_->cd_t;
446
447         /* Try to merge or append the two files */
448         tmpname = NULL;
449         if (merge_dlg.mergeType() == 0) {
450             /* chronological order */
451             in_filenames[0] = cap_file_->filename;
452             in_filenames[1] = file_name.toUtf8().data();
453             merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, FALSE);
454         } else if (merge_dlg.mergeType() <= 0) {
455             /* prepend file */
456             in_filenames[0] = file_name.toUtf8().data();
457             in_filenames[1] = cap_file_->filename;
458             merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE);
459         } else {
460             /* append file */
461             in_filenames[0] = cap_file_->filename;
462             in_filenames[1] = file_name.toUtf8().data();
463             merge_status = cf_merge_files(&tmpname, 2, in_filenames, file_type, TRUE);
464         }
465
466         if (merge_status != CF_OK) {
467             if (rfcode != NULL)
468                 dfilter_free(rfcode);
469             g_free(tmpname);
470             continue;
471         }
472
473         cf_close(cap_file_);
474
475         /* Try to open the merged capture file. */
476         cfile.window = this;
477         if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
478             /* We couldn't open it; fail. */
479             cfile.window = NULL;
480             if (rfcode != NULL)
481                 dfilter_free(rfcode);
482             g_free(tmpname);
483             return;
484         }
485
486         /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
487            it closed the previous capture file, and thus destroyed any
488            previous read filter attached to "cf"). */
489         cfile.rfcode = rfcode;
490
491         switch (cf_read(&cfile, FALSE)) {
492
493         case CF_READ_OK:
494         case CF_READ_ERROR:
495             /* Just because we got an error, that doesn't mean we were unable
496              to read any of the file; we handle what we could get from the
497              file. */
498             break;
499
500         case CF_READ_ABORTED:
501             /* The user bailed out of re-reading the capture file; the
502              capture file has been closed - just free the capture file name
503              string and return (without changing the last containing
504              directory). */
505             g_free(tmpname);
506             return;
507         }
508
509         /* Save the name of the containing directory specified in the path name,
510            if any; we can write over cf_merged_name, which is a good thing, given that
511            "get_dirname()" does write over its argument. */
512         wsApp->setLastOpenDir(get_dirname(tmpname));
513         g_free(tmpname);
514         df_combo_box_->setEditText(display_filter);
515         main_ui_->statusBar->showExpert();
516         return;
517     }
518
519 }
520
521 void MainWindow::importCaptureFile() {
522     ImportTextDialog import_dlg;
523
524     if (!testCaptureFileClose(FALSE, *new QString(tr(" before importing a new capture"))))
525         return;
526
527     import_dlg.exec();
528
529     if (import_dlg.result() != QDialog::Accepted) {
530         main_ui_->mainStack->setCurrentWidget(main_welcome_);
531         return;
532     }
533
534     openCaptureFile(import_dlg.capfileName());
535 }
536
537 void MainWindow::saveCaptureFile(capture_file *cf, bool stay_closed) {
538     QString file_name;
539     gboolean discard_comments;
540
541     if (cf->is_tempfile) {
542         /* This is a temporary capture file, so saving it means saving
543            it to a permanent file.  Prompt the user for a location
544            to which to save it.  Don't require that the file format
545            support comments - if it's a temporary capture file, it's
546            probably pcap-ng, which supports comments and, if it's
547            not pcap-ng, let the user decide what they want to do
548            if they've added comments. */
549         saveAsCaptureFile(cf, FALSE, stay_closed);
550     } else {
551         if (cf->unsaved_changes) {
552             cf_write_status_t status;
553
554             /* This is not a temporary capture file, but it has unsaved
555                changes, so saving it means doing a "safe save" on top
556                of the existing file, in the same format - no UI needed
557                unless the file has comments and the file's format doesn't
558                support them.
559
560                If the file has comments, does the file's format support them?
561                If not, ask the user whether they want to discard the comments
562                or choose a different format. */
563             switch (CaptureFileDialog::checkSaveAsWithComments(this, cf, cf->cd_t)) {
564
565             case SAVE:
566                 /* The file can be saved in the specified format as is;
567                    just drive on and save in the format they selected. */
568                 discard_comments = FALSE;
569                 break;
570
571             case SAVE_WITHOUT_COMMENTS:
572                 /* The file can't be saved in the specified format as is,
573                    but it can be saved without the comments, and the user
574                    said "OK, discard the comments", so save it in the
575                    format they specified without the comments. */
576                 discard_comments = TRUE;
577                 break;
578
579             case SAVE_IN_ANOTHER_FORMAT:
580                 /* There are file formats in which we can save this that
581                    support comments, and the user said not to delete the
582                    comments.  Do a "Save As" so the user can select
583                    one of those formats and choose a file name. */
584                 saveAsCaptureFile(cf, TRUE, stay_closed);
585                 return;
586
587             case CANCELLED:
588                 /* The user said "forget it".  Just return. */
589                 return;
590
591             default:
592                 /* Squelch warnings that discard_comments is being used
593                    uninitialized. */
594                 g_assert_not_reached();
595                 return;
596             }
597
598             /* XXX - cf->filename might get freed out from under us, because
599                the code path through which cf_save_packets() goes currently
600                closes the current file and then opens and reloads the saved file,
601                so make a copy and free it later. */
602             file_name = cf->filename;
603             status = cf_save_packets(cf, file_name.toUtf8().constData(), cf->cd_t, cf->iscompressed,
604                                      discard_comments, stay_closed);
605             switch (status) {
606
607             case CF_WRITE_OK:
608                 /* The save succeeded; we're done.
609                    If we discarded comments, redraw the packet list to reflect
610                    any packets that no longer have comments. */
611                 if (discard_comments)
612                     packet_list_queue_draw();
613                 break;
614
615             case CF_WRITE_ERROR:
616                 /* The write failed.
617                    XXX - OK, what do we do now?  Let them try a
618                    "Save As", in case they want to try to save to a
619                    different directory r file system? */
620                 break;
621
622             case CF_WRITE_ABORTED:
623                 /* The write was aborted; just drive on. */
624                 break;
625             }
626         }
627         /* Otherwise just do nothing. */
628     }
629 }
630
631 void MainWindow::saveAsCaptureFile(capture_file *cf, bool must_support_comments, bool stay_closed) {
632     QString file_name = "";
633     int file_type;
634     gboolean compressed;
635     cf_write_status_t status;
636     gchar   *dirname;
637     gboolean discard_comments = FALSE;
638
639     if (!cf) {
640         return;
641     }
642
643     for (;;) {
644         CaptureFileDialog save_as_dlg(this, cf);
645
646         switch (prefs.gui_fileopen_style) {
647
648         case FO_STYLE_LAST_OPENED:
649             /* The user has specified that we should start out in the last directory
650                we looked in.  If we've already opened a file, use its containing
651                directory, if we could determine it, as the directory, otherwise
652                use the "last opened" directory saved in the preferences file if
653                there was one. */
654             /* This is now the default behaviour in file_selection_new() */
655             break;
656
657         case FO_STYLE_SPECIFIED:
658             /* The user has specified that we should always start out in a
659                specified directory; if they've specified that directory,
660                start out by showing the files in that dir. */
661             if (prefs.gui_fileopen_dir[0] != '\0')
662                 save_as_dlg.setDirectory(prefs.gui_fileopen_dir);
663             break;
664         }
665
666         /* If the file has comments, does the format the user selected
667            support them?  If not, ask the user whether they want to
668            discard the comments or choose a different format. */
669         switch(save_as_dlg.saveAs(file_name, must_support_comments)) {
670
671         case SAVE:
672             /* The file can be saved in the specified format as is;
673                just drive on and save in the format they selected. */
674             discard_comments = FALSE;
675             break;
676
677         case SAVE_WITHOUT_COMMENTS:
678             /* The file can't be saved in the specified format as is,
679                but it can be saved without the comments, and the user
680                said "OK, discard the comments", so save it in the
681                format they specified without the comments. */
682             discard_comments = TRUE;
683             break;
684
685         case SAVE_IN_ANOTHER_FORMAT:
686             /* There are file formats in which we can save this that
687                support comments, and the user said not to delete the
688                comments.  The combo box of file formats has had the
689                formats that don't support comments trimmed from it,
690                so run the dialog again, to let the user decide
691                whether to save in one of those formats or give up. */
692             discard_comments = FALSE;
693             must_support_comments = TRUE;
694             continue;
695
696         case CANCELLED:
697             /* The user said "forget it".  Just get rid of the dialog box
698                and return. */
699             return;
700         }
701         file_type = save_as_dlg.selectedFileType();
702         compressed = save_as_dlg.isCompressed();
703
704         fileAddExtension(file_name, file_type, compressed);
705
706 //#ifndef _WIN32
707 //        /* If the file exists and it's user-immutable or not writable,
708 //                       ask the user whether they want to override that. */
709 //        if (!file_target_unwritable_ui(top_level, file_name.toUtf8().constData())) {
710 //            /* They don't.  Let them try another file name or cancel. */
711 //            continue;
712 //        }
713 //#endif
714
715         /* Attempt to save the file */
716         status = cf_save_packets(cf, file_name.toUtf8().constData(), file_type, compressed,
717                                  discard_comments, stay_closed);
718         switch (status) {
719
720         case CF_WRITE_OK:
721             /* The save succeeded; we're done. */
722             /* Save the directory name for future file dialogs. */
723             dirname = get_dirname(file_name.toUtf8().data());  /* Overwrites cf_name */
724             set_last_open_dir(dirname);
725             /* If we discarded comments, redraw the packet list to reflect
726                any packets that no longer have comments. */
727             if (discard_comments)
728                 packet_list_queue_draw();
729             return;
730
731         case CF_WRITE_ERROR:
732             /* The save failed; let the user try again. */
733             continue;
734
735         case CF_WRITE_ABORTED:
736             /* The user aborted the save; just return. */
737             return;
738         }
739     }
740     return;
741 }
742
743 void MainWindow::exportSelectedPackets() {
744     QString file_name = "";
745     int file_type;
746     gboolean compressed;
747     packet_range_t range;
748     cf_write_status_t status;
749     gchar   *dirname;
750     gboolean discard_comments = FALSE;
751
752     if (!cap_file_)
753         return;
754
755     /* Init the packet range */
756     packet_range_init(&range, cap_file_);
757     range.process_filtered = TRUE;
758     range.include_dependents = TRUE;
759
760     for (;;) {
761         CaptureFileDialog esp_dlg(this, cap_file_);
762
763         switch (prefs.gui_fileopen_style) {
764
765         case FO_STYLE_LAST_OPENED:
766             /* The user has specified that we should start out in the last directory
767                we looked in.  If we've already opened a file, use its containing
768                directory, if we could determine it, as the directory, otherwise
769                use the "last opened" directory saved in the preferences file if
770                there was one. */
771             /* This is now the default behaviour in file_selection_new() */
772             break;
773
774         case FO_STYLE_SPECIFIED:
775             /* The user has specified that we should always start out in a
776                specified directory; if they've specified that directory,
777                start out by showing the files in that dir. */
778             if (prefs.gui_fileopen_dir[0] != '\0')
779                 esp_dlg.setDirectory(prefs.gui_fileopen_dir);
780             break;
781         }
782
783         /* If the file has comments, does the format the user selected
784            support them?  If not, ask the user whether they want to
785            discard the comments or choose a different format. */
786         switch(esp_dlg.exportSelectedPackets(file_name, &range)) {
787
788         case SAVE:
789             /* The file can be saved in the specified format as is;
790                just drive on and save in the format they selected. */
791             discard_comments = FALSE;
792             break;
793
794         case SAVE_WITHOUT_COMMENTS:
795             /* The file can't be saved in the specified format as is,
796                but it can be saved without the comments, and the user
797                said "OK, discard the comments", so save it in the
798                format they specified without the comments. */
799             discard_comments = TRUE;
800             break;
801
802         case SAVE_IN_ANOTHER_FORMAT:
803             /* There are file formats in which we can save this that
804                support comments, and the user said not to delete the
805                comments.  The combo box of file formats has had the
806                formats that don't support comments trimmed from it,
807                so run the dialog again, to let the user decide
808                whether to save in one of those formats or give up. */
809             discard_comments = FALSE;
810             continue;
811
812         case CANCELLED:
813             /* The user said "forget it".  Just get rid of the dialog box
814                and return. */
815             return;
816         }
817
818         /*
819          * Check that we're not going to save on top of the current
820          * capture file.
821          * We do it here so we catch all cases ...
822          * Unfortunately, the file requester gives us an absolute file
823          * name and the read file name may be relative (if supplied on
824          * the command line). From Joerg Mayer.
825          */
826         if (files_identical(cap_file_->filename, file_name.toUtf8().constData())) {
827             QMessageBox msg_box;
828             gchar *display_basename = g_filename_display_basename(file_name.toUtf8().constData());
829
830             msg_box.setIcon(QMessageBox::Critical);
831             msg_box.setText(QString(tr("Unable to export to \"%1\".").arg(display_basename)));
832             msg_box.setInformativeText(tr("You cannot export packets to the current capture file."));
833             msg_box.setStandardButtons(QMessageBox::Ok);
834             msg_box.setDefaultButton(QMessageBox::Ok);
835             msg_box.exec();
836             g_free(display_basename);
837             continue;
838         }
839
840         file_type = esp_dlg.selectedFileType();
841         compressed = esp_dlg.isCompressed();
842         fileAddExtension(file_name, file_type, compressed);
843
844 //#ifndef _WIN32
845 //        /* If the file exists and it's user-immutable or not writable,
846 //                       ask the user whether they want to override that. */
847 //        if (!file_target_unwritable_ui(top_level, file_name.toUtf8().constData())) {
848 //            /* They don't.  Let them try another file name or cancel. */
849 //            continue;
850 //        }
851 //#endif
852
853         /* Attempt to save the file */
854         status = cf_export_specified_packets(cap_file_, file_name.toUtf8().constData(), &range, file_type, compressed);
855         switch (status) {
856
857         case CF_WRITE_OK:
858             /* The save succeeded; we're done. */
859             /* Save the directory name for future file dialogs. */
860             dirname = get_dirname(file_name.toUtf8().data());  /* Overwrites cf_name */
861             set_last_open_dir(dirname);
862             /* If we discarded comments, redraw the packet list to reflect
863                any packets that no longer have comments. */
864             if (discard_comments)
865                 packet_list_queue_draw();
866             return;
867
868         case CF_WRITE_ERROR:
869             /* The save failed; let the user try again. */
870             continue;
871
872         case CF_WRITE_ABORTED:
873             /* The user aborted the save; just return. */
874             return;
875         }
876     }
877     return;
878 }
879
880 void MainWindow::exportDissections(export_type_e export_type) {
881     ExportDissectionDialog ed_dlg(this, cap_file_, export_type);
882     packet_range_t range;
883
884     if (!cap_file_)
885         return;
886
887     /* Init the packet range */
888     packet_range_init(&range, cap_file_);
889     range.process_filtered = TRUE;
890     range.include_dependents = TRUE;
891
892     ed_dlg.exec();
893 }
894
895 void MainWindow::fileAddExtension(QString &file_name, int file_type, bool compressed) {
896     QString file_name_lower;
897     QString file_suffix;
898     GSList  *extensions_list;
899     gboolean add_extension;
900
901     /*
902      * Append the default file extension if there's none given by
903      * the user or if they gave one that's not one of the valid
904      * extensions for the file type.
905      */
906     file_name_lower = file_name.toLower();
907     extensions_list = wtap_get_file_extensions_list(file_type, FALSE);
908     if (extensions_list != NULL) {
909         GSList *extension;
910
911         /* We have one or more extensions for this file type.
912            Start out assuming we need to add the default one. */
913         add_extension = TRUE;
914
915         /* OK, see if the file has one of those extensions. */
916         for (extension = extensions_list; extension != NULL;
917              extension = g_slist_next(extension)) {
918             file_suffix += tr(".") + (char *)extension->data;
919             if (file_name_lower.endsWith(file_suffix)) {
920                 /*
921                  * The file name has one of the extensions for
922                  * this file type.
923                  */
924                 add_extension = FALSE;
925                 break;
926             }
927             file_suffix += ".gz";
928             if (file_name_lower.endsWith(file_suffix)) {
929                 /*
930                  * The file name has one of the extensions for
931                  * this file type.
932                  */
933                 add_extension = FALSE;
934                 break;
935             }
936         }
937     } else {
938         /* We have no extensions for this file type.  Don't add one. */
939         add_extension = FALSE;
940     }
941     if (add_extension) {
942         if (wtap_default_file_extension(file_type) != NULL) {
943             file_name += tr(".") + wtap_default_file_extension(file_type);
944             if (compressed) {
945                 file_name += ".gz";
946             }
947         }
948     }
949 }
950
951 bool MainWindow::testCaptureFileClose(bool from_quit, QString &before_what) {
952     bool   capture_in_progress = FALSE;
953
954     if (!cap_file_ || cap_file_->state == FILE_CLOSED)
955         return true; /* Already closed, nothing to do */
956
957 #ifdef HAVE_LIBPCAP
958     if (cap_file_->state == FILE_READ_IN_PROGRESS) {
959         /* This is true if we're reading a capture file *or* if we're doing
960          a live capture.  If we're reading a capture file, the main loop
961          is busy reading packets, and only accepting input from the
962          progress dialog, so we can't get here, so this means we're
963          doing a capture. */
964         capture_in_progress = TRUE;
965     }
966 #endif
967
968     if (prefs.gui_ask_unsaved) {
969         if (cap_file_->is_tempfile || capture_in_progress || cap_file_->unsaved_changes) {
970             QMessageBox msg_dialog;
971             QString question;
972             QPushButton *default_button;
973             int response;
974
975             msg_dialog.setIcon(QMessageBox::Question);
976
977             /* This is a temporary capture file, or there's a capture in
978                progress, or the file has unsaved changes; ask the user whether
979                to save the data. */
980             if (cap_file_->is_tempfile) {
981
982                 msg_dialog.setText(tr("You have unsaved packets"));
983                 msg_dialog.setInformativeText(tr("They will be lost if you don't save them."));
984
985                 if (capture_in_progress) {
986                     question.append(tr("Do you want to stop the capture and save the captured packets"));
987                 } else {
988                     question.append(tr("Do you want to save the captured packets"));
989                 }
990                 question.append(before_what).append(tr("?"));
991                 msg_dialog.setInformativeText(question);
992
993
994             } else {
995                 /*
996                  * Format the message.
997                  */
998                 if (capture_in_progress) {
999                     question.append(tr("Do you want to stop the capture and save the captured packets"));
1000                     question.append(before_what).append(tr("?"));
1001                     msg_dialog.setInformativeText(tr("Your captured packets will be lost if you don't save them."));
1002                 } else {
1003                     gchar *display_basename = g_filename_display_basename(cap_file_->filename);
1004                     question.append(QString(tr("Do you want to save the changes you've made to the capture file \"%1\"%2?"))
1005                                     .arg(display_basename)
1006                                     .arg(before_what)
1007                                     );
1008                     g_free(display_basename);
1009                     msg_dialog.setInformativeText(tr("Your changes will be lost if you don't save them."));
1010                 }
1011             }
1012
1013             // XXX Text comes from ui/gtk/stock_icons.[ch]
1014             // Note that the button roles differ from the GTK+ version.
1015             // Cancel = RejectRole
1016             // Save = AcceptRole
1017             // Don't Save = DestructiveRole
1018             msg_dialog.setStandardButtons(QMessageBox::Cancel);
1019
1020             if (capture_in_progress) {
1021                 default_button = msg_dialog.addButton(tr("Stop and Save"), QMessageBox::AcceptRole);
1022             } else {
1023                 default_button = msg_dialog.addButton(QMessageBox::Save);
1024             }
1025             msg_dialog.setDefaultButton(default_button);
1026
1027             if (from_quit) {
1028                 if (cap_file_->state == FILE_READ_IN_PROGRESS) {
1029                     msg_dialog.addButton(tr("Stop and Quit without Saving"), QMessageBox::DestructiveRole);
1030                 } else {
1031                     msg_dialog.addButton(tr("Quit without Saving"), QMessageBox::DestructiveRole);
1032                 }
1033             } else {
1034                 if (capture_in_progress) {
1035                     msg_dialog.addButton(tr("Stop and Continue without Saving"), QMessageBox::DestructiveRole);
1036                 } else {
1037                     msg_dialog.addButton(QMessageBox::Discard);
1038                 }
1039             }
1040
1041             response = msg_dialog.exec();
1042
1043             switch (response) {
1044
1045             case QMessageBox::Save:
1046 #ifdef HAVE_LIBPCAP
1047                 /* If there's a capture in progress, we have to stop the capture
1048              and then do the save. */
1049                 if (capture_in_progress)
1050                     captureStop();
1051 #endif
1052                 /* Save the file and close it */
1053                 saveCaptureFile(cap_file_, TRUE);
1054                 break;
1055
1056             case QMessageBox::Discard:
1057 #ifdef HAVE_LIBPCAP
1058                 /*
1059                  * If there's a capture in progress; we have to stop the capture
1060                  * and then do the close.
1061                  */
1062                 if (capture_in_progress)
1063                     captureStop();
1064 #endif
1065                 /* Just close the file, discarding changes */
1066                 cf_close(cap_file_);
1067                 return true;
1068                 break;
1069
1070             case QMessageBox::Cancel:
1071             default:
1072                 /* Don't close the file (and don't stop any capture in progress). */
1073                 return false; /* file not closed */
1074                 break;
1075             }
1076         } else {
1077             /* Unchanged file, just close it */
1078             cf_close(cap_file_);
1079         }
1080     } else {
1081         /* User asked not to be bothered by those prompts, just close it.
1082          XXX - should that apply only to saving temporary files? */
1083 #ifdef HAVE_LIBPCAP
1084         /* If there's a capture in progress, we have to stop the capture
1085            and then do the close. */
1086         if (capture_in_progress)
1087             captureStop();
1088 #endif
1089         cf_close(cap_file_);
1090     }
1091
1092     return true; /* File closed */
1093 }
1094
1095 void MainWindow::captureStop() {
1096     stopCapture();
1097
1098     while(cap_file_ && cap_file_->state == FILE_READ_IN_PROGRESS) {
1099         WiresharkApplication::processEvents();
1100     }
1101 }
1102
1103 // Menu state
1104
1105 /* Enable or disable menu items based on whether you have a capture file
1106    you've finished reading and, if you have one, whether it's been saved
1107    and whether it could be saved except by copying the raw packet data. */
1108 void MainWindow::setMenusForCaptureFile(bool force_disable)
1109 {
1110     if (force_disable || cap_file_ == NULL || cap_file_->state == FILE_READ_IN_PROGRESS) {
1111         /* We have no capture file or we're currently reading a file */
1112         main_ui_->actionFileMerge->setEnabled(false);
1113         main_ui_->actionFileClose->setEnabled(false);
1114         main_ui_->actionFileSave->setEnabled(false);
1115         main_ui_->actionFileSaveAs->setEnabled(false);
1116         main_ui_->actionFileExportPackets->setEnabled(false);
1117         main_ui_->menuFileExportPacketDissections->setEnabled(false);
1118         main_ui_->actionFileExportPacketBytes->setEnabled(false);
1119         main_ui_->actionFileExportSSLSessionKeys->setEnabled(false);
1120         main_ui_->menuFileExportObjects->setEnabled(false);
1121         main_ui_->actionViewReload->setEnabled(false);
1122     } else {
1123         main_ui_->actionFileMerge->setEnabled(cf_can_write_with_wiretap(cap_file_));
1124
1125         main_ui_->actionFileClose->setEnabled(true);
1126         /*
1127          * "Save" should be available only if:
1128          *
1129          *  the file has unsaved changes, and we can save it in some
1130          *  format through Wiretap
1131          *
1132          * or
1133          *
1134          *  the file is a temporary file and has no unsaved changes (so
1135          *  that "saving" it just means copying it).
1136          */
1137         main_ui_->actionFileSave->setEnabled(
1138                     (cap_file_->unsaved_changes && cf_can_write_with_wiretap(cap_file_)) ||
1139                     (cap_file_->is_tempfile && !cap_file_->unsaved_changes));
1140         /*
1141          * "Save As..." should be available only if:
1142          *
1143          *  we can save it in some format through Wiretap
1144          *
1145          * or
1146          *
1147          *  the file is a temporary file and has no unsaved changes (so
1148          *  that "saving" it just means copying it).
1149          */
1150         main_ui_->actionFileSaveAs->setEnabled(
1151                     cf_can_write_with_wiretap(cap_file_) ||
1152                     (cap_file_->is_tempfile && !cap_file_->unsaved_changes));
1153         /*
1154          * "Export Specified Packets..." should be available only if
1155          * we can write the file out in at least one format.
1156          */
1157         main_ui_->actionFileExportPackets->setEnabled(cf_can_write_with_wiretap(cap_file_));
1158         main_ui_->menuFileExportPacketDissections->setEnabled(true);
1159         main_ui_->actionFileExportPacketBytes->setEnabled(true);
1160         main_ui_->actionFileExportSSLSessionKeys->setEnabled(true);
1161         main_ui_->menuFileExportObjects->setEnabled(true);
1162         main_ui_->actionViewReload->setEnabled(true);
1163     }
1164 }
1165
1166 void MainWindow::setMenusForCaptureInProgress(bool capture_in_progress) {
1167     /* Either a capture was started or stopped; in either case, it's not
1168        in the process of stopping, so allow quitting. */
1169
1170     main_ui_->actionFileOpen->setEnabled(!capture_in_progress);
1171     main_ui_->menuOpenRecentCaptureFile->setEnabled(!capture_in_progress);
1172     main_ui_->menuFileExportPacketDissections->setEnabled(capture_in_progress);
1173     main_ui_->actionFileExportPacketBytes->setEnabled(capture_in_progress);
1174     main_ui_->actionFileExportSSLSessionKeys->setEnabled(capture_in_progress);
1175     main_ui_->menuFileExportObjects->setEnabled(capture_in_progress);
1176     main_ui_->menuFileSet->setEnabled(!capture_in_progress);
1177     main_ui_->actionFileQuit->setEnabled(true);
1178
1179     qDebug() << "FIX: packet list heading menu sensitivity";
1180     //    set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortAscending",
1181     //                         !capture_in_progress);
1182     //    set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/SortDescending",
1183     //                         !capture_in_progress);
1184     //    set_menu_sensitivity(ui_manager_packet_list_heading, "/PacketListHeadingPopup/NoSorting",
1185     //                         !capture_in_progress);
1186
1187 #ifdef HAVE_LIBPCAP
1188     main_ui_->actionCaptureOptions->setEnabled(!capture_in_progress);
1189     main_ui_->actionStartCapture->setEnabled(!capture_in_progress);
1190     main_ui_->actionStartCapture->setChecked(capture_in_progress);
1191     main_ui_->actionStopCapture->setEnabled(capture_in_progress);
1192     main_ui_->actionCaptureRestart->setEnabled(capture_in_progress);
1193 #endif /* HAVE_LIBPCAP */
1194
1195 }
1196
1197 void MainWindow::setMenusForCaptureStopping() {
1198     main_ui_->actionFileQuit->setEnabled(false);
1199 #ifdef HAVE_LIBPCAP
1200     main_ui_->actionStartCapture->setChecked(false);
1201     main_ui_->actionStopCapture->setEnabled(false);
1202     main_ui_->actionCaptureRestart->setEnabled(false);
1203 #endif /* HAVE_LIBPCAP */
1204 }
1205
1206 void MainWindow::setForCapturedPackets(bool have_captured_packets)
1207 {
1208     main_ui_->actionFilePrint->setEnabled(have_captured_packets);
1209
1210 //    set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/Print",
1211 //                         have_captured_packets);
1212
1213     main_ui_->actionEditFindPacket->setEnabled(have_captured_packets);
1214     main_ui_->actionEditFindNext->setEnabled(have_captured_packets);
1215     main_ui_->actionEditFindPrevious->setEnabled(have_captured_packets);
1216 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/ZoomIn",
1217 //                         have_captured_packets);
1218 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/ZoomOut",
1219 //                         have_captured_packets);
1220 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ViewMenu/NormalSize",
1221 //                         have_captured_packets);
1222
1223     main_ui_->actionGoGoToPacket->setEnabled(have_captured_packets);
1224     main_ui_->actionGoPreviousPacket->setEnabled(have_captured_packets);
1225     main_ui_->actionGoNextPacket->setEnabled(have_captured_packets);
1226     main_ui_->actionGoFirstPacket->setEnabled(have_captured_packets);
1227     main_ui_->actionGoLastPacket->setEnabled(have_captured_packets);
1228
1229 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/GoMenu/PreviousPacketInConversation",
1230 //                         have_captured_packets);
1231 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/GoMenu/NextPacketInConversation",
1232 //                         have_captured_packets);
1233 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/Summary",
1234 //                         have_captured_packets);
1235 //    set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/ProtocolHierarchy",
1236 //                         have_captured_packets);
1237 }
1238
1239 void MainWindow::setMenusForFileSet(bool enable_list_files) {
1240     bool enable_next = fileset_get_next() != NULL && enable_list_files;
1241     bool enable_prev = fileset_get_previous() != NULL && enable_list_files;
1242
1243     main_ui_->actionFileSetListFiles->setEnabled(enable_list_files);
1244     main_ui_->actionFileSetNextFile->setEnabled(enable_next);
1245     main_ui_->actionFileSetPreviousFile->setEnabled(enable_prev);
1246 }
1247
1248 void MainWindow::updateForUnsavedChanges() {
1249 //    set_display_filename(cf);
1250     setMenusForCaptureFile();
1251 //    set_toolbar_for_capture_file(cf);
1252
1253 }
1254
1255 /* Update main window items based on whether there's a capture in progress. */
1256 void MainWindow::setForCaptureInProgress(gboolean capture_in_progress)
1257 {
1258     setMenusForCaptureInProgress(capture_in_progress);
1259
1260 //#ifdef HAVE_LIBPCAP
1261 //    set_toolbar_for_capture_in_progress(capture_in_progress);
1262
1263 //    set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
1264 //#endif
1265 }
1266
1267 /*
1268  * Editor modelines
1269  *
1270  * Local Variables:
1271  * c-basic-offset: 4
1272  * tab-width: 8
1273  * indent-tabs-mode: nil
1274  * End:
1275  *
1276  * ex: set shiftwidth=4 tabstop=8 expandtab:
1277  * :indentSize=4:tabSize=8:noTabs=true:
1278  */