1 /* capture_file_dialog.cpp
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <wiretap/wtap.h>
26 #include "packet_range_group_box.h"
27 #include "capture_file_dialog.h"
31 #include "epan/packet-range.h"
32 #include "ui/win32/file_dlg_win32.h"
37 #include "../../epan/addr_resolv.h"
38 #include "../../epan/prefs.h"
39 #include "../../epan/filesystem.h"
40 #include "../../wsutil/nstime.h"
42 #include <wireshark_application.h>
44 #include <QGridLayout>
45 #include <QHBoxLayout>
46 #include <QVBoxLayout>
51 #include <QMessageBox>
52 #include <QSpacerItem>
55 #include <QPushButton>
58 // All of these routines are required by file_dlg_win32.c.
59 // We don't yet have a good place for them so we'll add them as stubs here.
63 // From gtk/capture_dlg.[ch]
64 /* capture start confirmed by "Save unsaved capture", so do it now */
65 extern void capture_start_confirmed(void) {
68 // From gtk/drag_and_drop.[ch]
69 /** Open a new file coming from drag and drop.
70 * @param cf_names_freeme the selection data reported from GTK
72 extern void dnd_open_file_cmd(gchar *cf_names_freeme) {
73 Q_UNUSED(cf_names_freeme);
76 // From gtk/menus.h & main_menubar.c
77 /** User pushed a recent file submenu item.
79 * @param widget parent widget
81 extern void menu_open_recent_file_cmd(gpointer action){
85 /** One of the name resolution menu items changed. */
86 extern void menu_name_resolution_changed(void) {
94 CaptureFileDialog::CaptureFileDialog(QWidget *parent, capture_file *cf, QString &display_filter) :
97 display_filter_(display_filter),
98 #if !defined(Q_OS_WIN)
101 help_topic_(TOPIC_ACTION_NONE)
106 #if !defined(Q_OS_WIN)
108 // http://qt-project.org/faq/answer/how_can_i_add_widgets_to_my_qfiledialog_instance
109 setOption(QFileDialog::DontUseNativeDialog, true);
110 QGridLayout *fd_grid = qobject_cast<QGridLayout*>(layout());
111 QHBoxLayout *h_box = new QHBoxLayout();
113 last_row_ = fd_grid->rowCount();
115 fd_grid->addItem(new QSpacerItem(1, 1), last_row_, 0);
116 fd_grid->addLayout(h_box, last_row_, 1);
119 // Left and right boxes for controls and preview
120 h_box->addLayout(&left_v_box_);
121 h_box->addLayout(&right_v_box_);
128 check_savability_t CaptureFileDialog::checkSaveAsWithComments(QWidget *
129 #if defined(Q_OS_WIN)
132 , capture_file *cf, int file_type) {
133 #if defined(Q_OS_WIN)
136 return win32_check_save_as_with_comments((HWND)parent->effectiveWinId(), cf, file_type);
138 guint32 comment_types;
139 QMessageBox msg_dialog;
142 /* What types of comments do we have? */
143 comment_types = cf_comment_types(cf);
145 /* Does the file's format support all the comments we have? */
146 if (wtap_dump_supports_comment_types(file_type, comment_types)) {
147 /* Yes. Let the save happen; we can save all the comments, so
148 there's no need to delete them. */
152 /* No. Are there formats in which we can write this file that
153 supports all the comments in this file? */
154 if (wtap_dump_can_write(cf->linktypes, comment_types)) {
155 QPushButton *default_button;
156 /* Yes. Offer the user a choice of "Save in a format that
157 supports comments", "Discard comments and save in the
158 format you selected", or "Cancel", meaning "don't bother
159 saving the file at all". */
160 msg_dialog.setIcon(QMessageBox::Question);
161 msg_dialog.setText(tr("This capture file contains comments."));
162 msg_dialog.setInformativeText(tr("The file format you chose doesn't support comments. "
163 "Do you want to save the capture in a format that supports comments "
164 "or discard the comments and save in the format you chose?"));
165 msg_dialog.setStandardButtons(QMessageBox::Cancel);
166 // The predefined roles don't really match the tasks at hand...
167 msg_dialog.addButton(tr("Discard comments and save"), QMessageBox::DestructiveRole);
168 default_button = msg_dialog.addButton(tr("Save in another format"), QMessageBox::AcceptRole);
169 msg_dialog.setDefaultButton(default_button);
171 /* No. Offer the user a choice of "Discard comments and
172 save in the format you selected" or "Cancel". */
173 msg_dialog.setIcon(QMessageBox::Question);
174 msg_dialog.setText(tr("This capture file contains comments."));
175 msg_dialog.setInformativeText(tr("No file format in which it can be saved supports comments. "
176 "Do you want to discard the comments and save in the format you chose?"));
177 msg_dialog.setStandardButtons(QMessageBox::Cancel);
178 msg_dialog.addButton(tr("Discard comments and save"), QMessageBox::DestructiveRole);
179 msg_dialog.setDefaultButton(QMessageBox::Cancel);
182 response = msg_dialog.exec();
186 case QMessageBox::Save:
187 /* OK, the only other format we support is pcap-ng. Make that
188 the one and only format in the combo box, and return to
189 let the user continue with the dialog.
191 XXX - removing all the formats from the combo box will clear
192 the compressed checkbox; get the current value and restore
195 XXX - we know pcap-ng can be compressed; if we ever end up
196 supporting saving comments in a format that *can't* be
197 compressed, such as NetMon format, we must check this. */
198 /* XXX - need a compressed checkbox here! */
199 return SAVE_IN_ANOTHER_FORMAT;
201 case QMessageBox::Discard:
202 /* Save without the comments and, if that succeeds, delete the
204 return SAVE_WITHOUT_COMMENTS;
206 case QMessageBox::Cancel:
216 // You have to use open, merge, saveAs, or exportPackets. We should
217 // probably just make each type a subclass.
218 int CaptureFileDialog::exec() {
219 return QDialog::Rejected;
226 int CaptureFileDialog::selectedFileType() {
230 bool CaptureFileDialog::isCompressed() {
234 int CaptureFileDialog::open(QString &file_name) {
235 GString *fname = g_string_new(file_name.toUtf8().constData());
236 GString *dfilter = g_string_new(display_filter_.toUtf8().constData());
239 // XXX Add a widget->HWND routine to qt_ui_utils and use it instead.
240 wof_status = win32_open_file((HWND)parentWidget()->effectiveWinId(), fname, dfilter);
241 file_name = fname->str;
242 display_filter_ = dfilter->str;
244 g_string_free(fname, TRUE);
245 g_string_free(dfilter, TRUE);
247 return (int) wof_status;
250 check_savability_t CaptureFileDialog::saveAs(QString &file_name, bool must_support_all_comments) {
251 GString *fname = g_string_new(file_name.toUtf8().constData());
254 wsf_status = win32_save_as_file((HWND)parentWidget()->effectiveWinId(), cap_file_, fname, &file_type_, &compressed_, must_support_all_comments);
255 file_name = fname->str;
257 g_string_free(fname, TRUE);
260 return win32_check_save_as_with_comments((HWND)parentWidget()->effectiveWinId(), cap_file_, file_type_);
266 check_savability_t CaptureFileDialog::exportSelectedPackets(QString &file_name, packet_range_t *range) {
267 GString *fname = g_string_new(file_name.toUtf8().constData());
268 gboolean wespf_status;
270 wespf_status = win32_export_specified_packets_file((HWND)parentWidget()->effectiveWinId(), cap_file_, fname, &file_type_, &compressed_, range);
271 file_name = fname->str;
273 g_string_free(fname, TRUE);
276 return win32_check_save_as_with_comments((HWND)parentWidget()->effectiveWinId(), cap_file_, file_type_);
282 int CaptureFileDialog::merge(QString &file_name) {
283 GString *fname = g_string_new(file_name.toUtf8().constData());
284 GString *dfilter = g_string_new(display_filter_.toUtf8().constData());
287 wmf_status = win32_merge_file((HWND)parentWidget()->effectiveWinId(), fname, dfilter, &merge_type_);
288 file_name = fname->str;
289 display_filter_ = dfilter->str;
291 g_string_free(fname, TRUE);
292 g_string_free(dfilter, TRUE);
294 return (int) wmf_status;
297 int CaptureFileDialog::mergeType() {
301 #else // not Q_OS_WINDOWS
302 QString CaptureFileDialog::fileExtensionType(int et, bool extension_globs)
305 GSList *extensions_list;
308 filter = wtap_get_file_extension_type_name(et);
310 if (!extension_globs) {
316 extensions_list = wtap_get_file_extension_type_extensions(et);
318 /* Construct the list of patterns. */
319 for (extension = extensions_list; extension != NULL;
320 extension = g_slist_next(extension)) {
321 if (!filter.endsWith('('))
324 filter += (char *)extension->data;
326 wtap_free_extensions_list(extensions_list);
329 /* XXX - does QStringList's destructor destroy the strings in the list? */
332 QString CaptureFileDialog::fileType(int ft, bool extension_globs)
335 GSList *extensions_list;
337 filter = wtap_file_type_subtype_string(ft);
339 if (!extension_globs) {
345 extensions_list = wtap_get_file_extensions_list(ft, TRUE);
346 if (extensions_list == NULL) {
347 /* This file type doesn't have any particular extension
348 conventionally used for it, so we'll just use "*.*"
349 as the pattern; on Windows, that matches all file names
350 - even those with no extension - so we don't need to
351 worry about compressed file extensions. (It does not
352 do so on UN*X; the right pattern on UN*X would just
357 /* Construct the list of patterns. */
358 for (extension = extensions_list; extension != NULL;
359 extension = g_slist_next(extension)) {
360 if (!filter.endsWith('('))
363 filter += (char *)extension->data;
365 wtap_free_extensions_list(extensions_list);
369 /* XXX - does QStringList's destructor destroy the strings in the list? */
372 QStringList CaptureFileDialog::buildFileOpenTypeList() {
375 GSList *extensions_list;
380 * Microsoft's UI guidelines say, of the file filters in open and
383 * For meta-filters, remove the file extension list to eliminate
384 * clutter. Examples: "All files," "All pictures," "All music,"
387 * On both Windows XP and Windows 7, Wordpad doesn't do that, but
390 * XXX - on Windows, does Qt do that here? For "All Capture Files",
391 * the filter will be a bit long, so it *really* shouldn't be shown.
392 * What about other platforms?
394 /* Add the "All Files" entry. */
395 filters << QString(tr("All Files (*.*)"));
398 * Add an "All Capture Files" entry, with all the extensions we
401 filter = "All Capture Files";
404 * Construct its list of patterns from a list of all extensions
407 extensions_list = wtap_get_all_file_extensions_list();
409 for (extension = extensions_list; extension != NULL;
410 extension = g_slist_next(extension)) {
413 filter += (char *)extension->data;
419 /* Include all the file types Wireshark supports. */
420 for (et = 0; et < wtap_get_num_file_type_extensions(); et++) {
421 filters << fileExtensionType(et);
427 void CaptureFileDialog::addPreview(QVBoxLayout &v_box) {
428 QGridLayout *preview_grid = new QGridLayout();
431 preview_labels_.clear();
432 v_box.addLayout(preview_grid);
434 preview_grid->setColumnStretch(0, 0);
435 preview_grid->setColumnStretch(1, 10);
437 lbl = new QLabel(tr("Format:"));
438 preview_grid->addWidget(lbl, 0, 0);
439 preview_grid->addWidget(&preview_format_, 0, 1);
440 preview_labels_ << lbl << &preview_format_;
442 lbl = new QLabel(tr("Size:"));
443 preview_grid->addWidget(lbl, 1, 0);
444 preview_grid->addWidget(&preview_size_, 1, 1);
445 preview_labels_ << lbl << &preview_size_;
447 lbl = new QLabel(tr("Packets:"));
448 preview_grid->addWidget(lbl, 2, 0);
449 preview_grid->addWidget(&preview_packets_, 2, 1);
450 preview_labels_ << lbl << &preview_packets_;
452 lbl = new QLabel(tr("First Packet:"));
453 preview_grid->addWidget(lbl, 3, 0);
454 preview_grid->addWidget(&preview_first_, 3, 1);
455 preview_labels_ << lbl << &preview_first_;
457 lbl = new QLabel(tr("Elapsed Time:"));
458 preview_grid->addWidget(lbl, 4, 0);
459 preview_grid->addWidget(&preview_elapsed_, 4, 1);
460 preview_labels_ << lbl << &preview_elapsed_;
462 connect(this, SIGNAL(currentChanged(const QString &)), this, SLOT(preview(const QString &)));
467 void CaptureFileDialog::addMergeControls(QVBoxLayout &v_box) {
469 merge_prepend_.setText(tr("Prepend packets"));
470 merge_prepend_.setToolTip(tr("Insert packets from the selected file before the current file. Packet timestamps will be ignored."));
471 v_box.addWidget(&merge_prepend_, 0, Qt::AlignTop);
473 merge_chrono_.setText(tr("Merge chronologically"));
474 merge_chrono_.setToolTip(tr("Insert packets in chronological order."));
475 merge_chrono_.setChecked(true);
476 v_box.addWidget(&merge_chrono_, 0, Qt::AlignTop);
478 merge_append_.setText(tr("Append packets"));
479 merge_append_.setToolTip(tr("Insert packets from the selected file after the current file. Packet timestamps will be ignored."));
480 v_box.addWidget(&merge_append_, 0, Qt::AlignTop);
483 int CaptureFileDialog::selectedFileType() {
484 return type_hash_.value(selectedNameFilter(), -1);
487 bool CaptureFileDialog::isCompressed() {
488 return compress_.isChecked();
491 void CaptureFileDialog::addDisplayFilterEdit() {
492 QGridLayout *fd_grid = qobject_cast<QGridLayout*>(layout());
494 fd_grid->addWidget(new QLabel(tr("Display Filter:")), last_row_, 0);
496 display_filter_edit_ = new DisplayFilterEdit(this, true);
497 display_filter_edit_->setText(display_filter_);
498 fd_grid->addWidget(display_filter_edit_, last_row_, 1);
502 void CaptureFileDialog::addResolutionControls(QVBoxLayout &v_box) {
503 mac_res_.setText(tr("&MAC name resolution"));
504 mac_res_.setChecked(gbl_resolv_flags.mac_name);
505 v_box.addWidget(&mac_res_, 0, Qt::AlignTop);
507 transport_res_.setText(tr("&Transport name resolution"));
508 transport_res_.setChecked(gbl_resolv_flags.transport_name);
509 v_box.addWidget(&transport_res_, 0, Qt::AlignTop);
511 network_res_.setText(tr("&Network name resolution"));
512 network_res_.setChecked(gbl_resolv_flags.network_name);
513 v_box.addWidget(&network_res_, 0, Qt::AlignTop);
515 external_res_.setText(tr("&External name resolver"));
516 external_res_.setChecked(gbl_resolv_flags.use_external_net_name_resolver);
517 v_box.addWidget(&external_res_, 0, Qt::AlignTop);
520 void CaptureFileDialog::addGzipControls(QVBoxLayout &v_box) {
521 compress_.setText(tr("Compress with g&zip"));
522 if (cap_file_->iscompressed && wtap_dump_can_compress(default_ft_)) {
523 compress_.setChecked(true);
525 compress_.setChecked(false);
527 v_box.addWidget(&compress_, 0, Qt::AlignTop);
531 void CaptureFileDialog::addRangeControls(QVBoxLayout &v_box, packet_range_t *range) {
532 packet_range_group_box_.initRange(range);
533 v_box.addWidget(&packet_range_group_box_, 0, Qt::AlignTop);
536 QDialogButtonBox *CaptureFileDialog::addHelpButton(topic_action_e help_topic)
538 // This doesn't appear to be documented anywhere but it seems pretty obvious
540 QDialogButtonBox *button_box = findChild<QDialogButtonBox *>();
542 help_topic_ = help_topic;
545 button_box->addButton(QDialogButtonBox::Help);
546 connect(button_box, SIGNAL(helpRequested()), this, SLOT(on_buttonBox_helpRequested()));
551 int CaptureFileDialog::open(QString &file_name) {
552 setWindowTitle(tr("Wireshark: Open Capture File"));
553 setNameFilters(buildFileOpenTypeList());
554 setFileMode(QFileDialog::ExistingFile);
556 addDisplayFilterEdit();
557 addResolutionControls(left_v_box_);
558 addPreview(right_v_box_);
559 addHelpButton(HELP_OPEN_DIALOG);
561 // Grow the dialog to account for the extra widgets.
562 resize(width(), height() + left_v_box_.minimumSize().height() + display_filter_edit_->minimumSize().height());
564 display_filter_.clear();
566 if (!file_name.isEmpty()) {
567 selectFile(file_name);
570 if (QFileDialog::exec() && selectedFiles().length() > 0) {
571 file_name = selectedFiles()[0];
572 display_filter_.append(display_filter_edit_->text());
574 gbl_resolv_flags.mac_name = mac_res_.isChecked();
575 gbl_resolv_flags.transport_name = transport_res_.isChecked();
576 gbl_resolv_flags.network_name = network_res_.isChecked();
577 gbl_resolv_flags.use_external_net_name_resolver = external_res_.isChecked();
579 return QDialog::Accepted;
581 return QDialog::Rejected;
585 check_savability_t CaptureFileDialog::saveAs(QString &file_name, bool must_support_all_comments) {
586 setWindowTitle(tr("Wireshark: Save Capture File As"));
587 // XXX There doesn't appear to be a way to use setNameFilters without restricting
588 // what the user can select. We might want to use our own combobox instead and
589 // let the user select anything.
590 setNameFilters(buildFileSaveAsTypeList(must_support_all_comments));
591 setAcceptMode(QFileDialog::AcceptSave);
592 setLabelText(FileType, tr("Save as:"));
594 addGzipControls(left_v_box_);
595 addHelpButton(HELP_SAVE_DIALOG);
597 // Grow the dialog to account for the extra widgets.
598 resize(width(), height() + left_v_box_.minimumSize().height());
600 if (!file_name.isEmpty()) {
601 selectFile(file_name);
604 if (QFileDialog::exec() && selectedFiles().length() > 0) {
605 file_name = selectedFiles()[0];
606 return checkSaveAsWithComments(this, cap_file_, selectedFileType());
611 check_savability_t CaptureFileDialog::exportSelectedPackets(QString &file_name, packet_range_t *range) {
612 QDialogButtonBox *button_box;
614 setWindowTitle(tr("Wireshark: Export Specified Packets"));
615 // XXX See comment in ::saveAs regarding setNameFilters
616 setNameFilters(buildFileSaveAsTypeList(false));
617 setAcceptMode(QFileDialog::AcceptSave);
618 setLabelText(FileType, tr("Export as:"));
620 addRangeControls(left_v_box_, range);
621 addGzipControls(right_v_box_);
622 button_box = addHelpButton(HELP_EXPORT_FILE_DIALOG);
625 save_bt_ = button_box->button(QDialogButtonBox::Save);
627 connect(&packet_range_group_box_, SIGNAL(validityChanged(bool)),
628 save_bt_, SLOT(setEnabled(bool)));
632 // Grow the dialog to account for the extra widgets.
633 resize(width(), height() + (packet_range_group_box_.height() * 2 / 3));
635 if (!file_name.isEmpty()) {
636 selectFile(file_name);
639 if (QFileDialog::exec() && selectedFiles().length() > 0) {
640 file_name = selectedFiles()[0];
641 return checkSaveAsWithComments(this, cap_file_, selectedFileType());
646 int CaptureFileDialog::merge(QString &file_name) {
647 setWindowTitle(tr("Wireshark: Merge Capture File"));
648 setNameFilters(buildFileOpenTypeList());
649 setFileMode(QFileDialog::ExistingFile);
651 addDisplayFilterEdit();
652 addMergeControls(left_v_box_);
653 addPreview(right_v_box_);
654 addHelpButton(HELP_MERGE_DIALOG);
657 display_filter_.clear();
659 // Grow the dialog to account for the extra widgets.
660 resize(width(), height() + right_v_box_.minimumSize().height() + display_filter_edit_->minimumSize().height());
662 if (QFileDialog::exec() && selectedFiles().length() > 0) {
663 file_name.append(selectedFiles()[0]);
664 display_filter_.append(display_filter_edit_->text());
666 return QDialog::Accepted;
668 return QDialog::Rejected;
672 QStringList CaptureFileDialog::buildFileSaveAsTypeList(bool must_support_all_comments) {
674 guint32 required_comment_types;
675 GArray *savable_file_types_subtypes;
680 /* What types of comments do we have to support? */
681 if (must_support_all_comments)
682 required_comment_types = cf_comment_types(cap_file_); /* all the ones the file has */
684 required_comment_types = 0; /* none of them */
686 /* What types of file can we save this file as? */
687 savable_file_types_subtypes = wtap_get_savable_file_types_subtypes(cap_file_->cd_t,
688 cap_file_->linktypes,
689 required_comment_types);
691 if (savable_file_types_subtypes != NULL) {
694 /* OK, we have at least one file type we can save this file as.
695 (If we didn't, we shouldn't have gotten here in the first
696 place.) Add them all to the combo box. */
697 for (i = 0; i < savable_file_types_subtypes->len; i++) {
698 ft = g_array_index(savable_file_types_subtypes, int, i);
700 default_ft_ = ft; /* first file type is the default */
701 file_type = fileType(ft);
702 filters << file_type;
703 type_hash_[file_type] = ft;
705 g_array_free(savable_file_types_subtypes, TRUE);
711 int CaptureFileDialog::mergeType() {
712 if (merge_prepend_.isChecked())
714 else if (merge_append_.isChecked())
724 /* do a preview run on the currently selected capture file */
725 void CaptureFileDialog::preview(const QString & path)
731 const struct wtap_pkthdr *phdr;
732 double start_time = 0; /* seconds, with nsec resolution */
733 double stop_time = 0; /* seconds, with nsec resolution */
735 unsigned int packets = 0;
736 bool timed_out = FALSE;
741 unsigned int elapsed_time;
743 // Follow the same steps as ui/win32/file_dlg_win32.c
745 foreach (QLabel *lbl, preview_labels_) {
746 lbl->setEnabled(false);
749 preview_format_.setText(tr("-"));
750 preview_size_.setText(tr("-"));
751 preview_packets_.setText(tr("-"));
752 preview_first_.setText(tr("-"));
753 preview_elapsed_.setText(tr("-"));
755 if (path.length() < 1) {
759 if (test_for_directory(path.toUtf8().data()) == EISDIR) {
760 preview_format_.setText(tr("directory"));
764 wth = wtap_open_offline(path.toUtf8().data(), &err, &err_info, TRUE);
766 if(err == WTAP_ERR_FILE_UNKNOWN_FORMAT) {
767 preview_format_.setText(tr("unknown file format"));
769 preview_format_.setText(tr("error opening file"));
775 foreach (QLabel *lbl, preview_labels_) {
776 lbl->setEnabled(true);
780 preview_format_.setText(QString::fromUtf8(wtap_file_type_subtype_string(wtap_file_type_subtype(wth))));
783 preview_size_.setText(QString(tr("%1 bytes")).arg(wtap_file_size(wth, &err)));
786 while ( (wtap_read(wth, &err, &err_info, &data_offset)) ) {
787 phdr = wtap_phdr(wth);
788 cur_time = wtap_nstime_to_sec(&phdr->ts);
790 start_time = cur_time;
791 stop_time = cur_time;
793 if (cur_time < start_time) {
794 start_time = cur_time;
796 if (cur_time > stop_time){
797 stop_time = cur_time;
801 if(packets%1000 == 0) {
802 /* do we have a timeout? */
804 if(time_current-time_preview >= (time_t) prefs.gui_fileopen_preview) {
812 preview_packets_.setText(QString(tr("error after reading %1 packets")).arg(packets));
818 preview_packets_.setText(QString(tr("more than %1 (preview timeout)")).arg(packets));
820 preview_packets_.setText(QString("%1").arg(packets));
824 ti_time = (long)start_time;
825 ti_tm = localtime( &ti_time );
827 preview_first_.setText(QString().sprintf(
828 "%04d-%02d-%02d %02d:%02d:%02d",
829 ti_tm->tm_year + 1900,
837 preview_first_.setText(tr("?"));
841 elapsed_time = (unsigned int)(stop_time-start_time);
843 preview_elapsed_.setText(tr("unknown"));
844 } else if(elapsed_time/86400) {
845 preview_elapsed_.setText(QString().sprintf("%02u days %02u:%02u:%02u",
846 elapsed_time/86400, elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60));
848 preview_elapsed_.setText(QString().sprintf("%02u:%02u:%02u",
849 elapsed_time%86400/3600, elapsed_time%3600/60, elapsed_time%60));
855 void CaptureFileDialog::on_buttonBox_helpRequested()
857 if (help_topic_ != TOPIC_ACTION_NONE) wsApp->helpTopicAction(help_topic_);
860 #endif // Q_OS_WINDOWS
868 * indent-tabs-mode: nil
871 * ex: set shiftwidth=4 tabstop=8 expandtab:
872 * :indentSize=4:tabSize=8:noTabs=true: