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