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