aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Knall <rknall@gmail.com>2019-11-12 16:39:19 +0100
committerRoland Knall <rknall@gmail.com>2019-11-17 12:20:29 +0000
commitb3f240dbf8c5e24cf420e977d8544c4abb40c80e (patch)
treec783c4f210f09ed7c8ab227e9923953a6d8872e0
parent7d2e3fa8f5115e8cdddd5ea7a05797151a3965e7 (diff)
Qt: Multiselection in PacketList
This implements multi-selection for the PacketList. It allows multiple lines to be selected, and either drag/drop them to a text editor or use Ctrl/Cmd+C to copy the content to a clipboard. Opening the context menu disables the selection, and it does not change the underlying currently selection. This is done on purpose, as multi-selection is a copy-task only functionality at this point Export & Print work as expected, exporting just the selected items. Same goes for the copy menu, which has the additional entries for copying the list elements Bug: 14612 Change-Id: I77960aa1ab1d172a21abfa469baac0cd57f9f9d9 Reviewed-on: https://code.wireshark.org/review/35073 Petri-Dish: Roland Knall <rknall@gmail.com> Reviewed-by: Stig Bjørlykke <stig@bjorlykke.org> Tested-by: Petri Dish Buildbot Reviewed-by: Roland Knall <rknall@gmail.com>
-rw-r--r--ui/packet_range.c88
-rw-r--r--ui/packet_range.h10
-rw-r--r--ui/qt/capture_file_dialog.cpp15
-rw-r--r--ui/qt/capture_file_dialog.h4
-rw-r--r--ui/qt/export_dissection_dialog.cpp4
-rw-r--r--ui/qt/export_dissection_dialog.h2
-rw-r--r--ui/qt/main_status_bar.cpp20
-rw-r--r--ui/qt/main_window.cpp52
-rw-r--r--ui/qt/main_window.h14
-rw-r--r--ui/qt/main_window.ui30
-rw-r--r--ui/qt/main_window_slots.cpp119
-rw-r--r--ui/qt/models/packet_list_model.cpp66
-rw-r--r--ui/qt/models/packet_list_model.h4
-rw-r--r--ui/qt/models/related_packet_delegate.cpp26
-rw-r--r--ui/qt/packet_list.cpp237
-rw-r--r--ui/qt/packet_list.h16
-rw-r--r--ui/qt/packet_range_group_box.cpp22
-rw-r--r--ui/qt/packet_range_group_box.h2
-rw-r--r--ui/qt/print_dialog.cpp6
-rw-r--r--ui/qt/print_dialog.h9
-rw-r--r--ui/qt/proto_tree.cpp19
-rw-r--r--ui/qt/proto_tree.h2
-rw-r--r--ui/qt/wireshark_en.ts20
-rw-r--r--ui/win32/file_dlg_win32.c22
24 files changed, 639 insertions, 170 deletions
diff --git a/ui/packet_range.c b/ui/packet_range.c
index 802fdea735..3ad148651a 100644
--- a/ui/packet_range.c
+++ b/ui/packet_range.c
@@ -31,12 +31,12 @@ static void packet_range_calc(packet_range_t *range) {
frame_data *packet;
- range->selected_packet = 0;
mark_low = 0;
mark_high = 0;
range->mark_range_cnt = 0;
range->ignored_cnt = 0;
+ range->ignored_selection_range_cnt = 0;
range->ignored_marked_cnt = 0;
range->ignored_mark_range_cnt = 0;
range->ignored_user_range_cnt = 0;
@@ -49,6 +49,7 @@ static void packet_range_calc(packet_range_t *range) {
range->displayed_mark_range_cnt = 0;
range->displayed_plus_dependents_cnt = 0;
range->displayed_ignored_cnt = 0;
+ range->displayed_ignored_selection_range_cnt = 0;
range->displayed_ignored_marked_cnt = 0;
range->displayed_ignored_mark_range_cnt = 0;
range->displayed_ignored_user_range_cnt = 0;
@@ -79,8 +80,8 @@ static void packet_range_calc(packet_range_t *range) {
for(framenum = 1; framenum <= range->cf->count; framenum++) {
packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
- if (range->cf->current_frame == packet) {
- range->selected_packet = framenum;
+ if (range->cf->current_frame == packet && range->selection_range == NULL ) {
+ range_add_value(NULL, &(range->selection_range), framenum);
}
if (packet->passed_dfilter) {
range->displayed_cnt++;
@@ -145,17 +146,6 @@ static void packet_range_calc(packet_range_t *range) {
}
}
-#if 0
- /* in case we marked just one packet, we add 1. */
- if (range->cf->marked_count != 0) {
- range->mark_range = mark_high - mark_low + 1;
- }
-
- /* in case we marked just one packet, we add 1. */
- if (range->displayed_marked_cnt != 0) {
- range->displayed_mark_range = displayed_mark_high - displayed_mark_low + 1;
- }
-#endif
}
}
@@ -211,6 +201,37 @@ static void packet_range_calc_user(packet_range_t *range) {
}
}
+static void packet_range_calc_selection(packet_range_t *range) {
+ guint32 framenum;
+ frame_data *packet;
+
+ range->selection_range_cnt = 0;
+ range->ignored_selection_range_cnt = 0;
+ range->displayed_selection_range_cnt = 0;
+ range->displayed_ignored_selection_range_cnt = 0;
+
+ g_assert(range->cf != NULL);
+
+ if (range->cf->provider.frames != NULL) {
+ for (framenum = 1; framenum <= range->cf->count; framenum++) {
+ packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
+
+ if (value_is_in_range(range->selection_range, framenum)) {
+ range->selection_range_cnt++;
+ if (packet->ignored) {
+ range->ignored_selection_range_cnt++;
+ }
+ if (packet->passed_dfilter) {
+ range->displayed_selection_range_cnt++;
+ if (packet->ignored) {
+ range->displayed_ignored_selection_range_cnt++;
+ }
+ }
+ }
+ }
+ }
+}
+
/* init the range struct */
void packet_range_init(packet_range_t *range, capture_file *cf) {
@@ -218,15 +239,18 @@ void packet_range_init(packet_range_t *range, capture_file *cf) {
memset(range, 0, sizeof(packet_range_t));
range->process = range_process_all;
range->user_range = NULL;
+ range->selection_range = NULL;
range->cf = cf;
/* calculate all packet range counters */
packet_range_calc(range);
packet_range_calc_user(range);
+ packet_range_calc_selection(range);
}
void packet_range_cleanup(packet_range_t *range) {
wmem_free(NULL, range->user_range);
+ wmem_free(NULL, range->selection_range);
}
/* check whether the packet range is OK */
@@ -235,6 +259,10 @@ convert_ret_t packet_range_check(packet_range_t *range) {
/* Not valid - return the error. */
return range->user_range_status;
}
+ if (range->process == range_process_selected && range->selection_range == NULL) {
+ return range->selection_range_status;
+ }
+
return CVT_NO_ERROR;
}
@@ -270,13 +298,9 @@ range_process_e packet_range_process_packet(packet_range_t *range, frame_data *f
case(range_process_all):
break;
case(range_process_selected):
- if (range->selected_done) {
- return range_processing_finished;
- }
- if (fdata->num != range->cf->current_frame->num) {
+ if (value_is_in_range(range->selection_range, fdata->num) == FALSE) {
return range_process_next;
}
- range->selected_done = TRUE;
break;
case(range_process_marked):
if (fdata->marked == FALSE) {
@@ -356,6 +380,32 @@ void packet_range_convert_str(packet_range_t *range, const gchar *es)
packet_range_calc_user(range);
} /* packet_range_convert_str */
+void packet_range_convert_selection_str(packet_range_t *range, const char *es)
+{
+ range_t *new_range;
+ convert_ret_t ret;
+
+ if (range->selection_range != NULL)
+ wmem_free(NULL, range->selection_range);
+
+ g_assert(range->cf != NULL);
+
+ ret = range_convert_str(NULL, &new_range, es, range->cf->count);
+ if (ret != CVT_NO_ERROR) {
+ /* range isn't valid */
+ range->selection_range = NULL;
+ range->selection_range_status = ret;
+ range->selection_range_cnt = 0;
+ range->ignored_selection_range_cnt = 0;
+ range->displayed_selection_range_cnt = 0;
+ range->displayed_ignored_selection_range_cnt = 0;
+ return;
+ }
+ range->selection_range = new_range;
+
+ /* calculate new user specified packet range counts */
+ packet_range_calc_selection(range);
+}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
diff --git a/ui/packet_range.h b/ui/packet_range.h
index 1622648199..6e7d34d118 100644
--- a/ui/packet_range.h
+++ b/ui/packet_range.h
@@ -47,16 +47,19 @@ typedef struct packet_range_tag {
convert_ret_t user_range_status;
/* calculated values */
- guint32 selected_packet; /* the currently selected packet */
+ range_t *selection_range; /* the currently selected packets */
+ convert_ret_t selection_range_status;
/* current packet counts (captured) */
capture_file *cf; /* Associated capture file. */
guint32 mark_range_cnt; /* packets in marked range */
guint32 user_range_cnt; /* packets in user specified range */
+ guint32 selection_range_cnt; /* packets in the selected range */
guint32 ignored_cnt; /* packets ignored */
guint32 ignored_marked_cnt; /* packets ignored and marked */
guint32 ignored_mark_range_cnt; /* packets ignored in marked range */
guint32 ignored_user_range_cnt; /* packets ignored in user specified range */
+ guint32 ignored_selection_range_cnt; /* packets ignored in the selected range */
/* current packet counts (displayed) */
guint32 displayed_cnt;
@@ -64,10 +67,12 @@ typedef struct packet_range_tag {
guint32 displayed_marked_cnt;
guint32 displayed_mark_range_cnt;
guint32 displayed_user_range_cnt;
+ guint32 displayed_selection_range_cnt;
guint32 displayed_ignored_cnt;
guint32 displayed_ignored_marked_cnt;
guint32 displayed_ignored_mark_range_cnt;
guint32 displayed_ignored_user_range_cnt;
+ guint32 displayed_ignored_selection_range_cnt;
/* "enumeration" values */
gboolean marked_range_active; /* marked range is currently processed */
@@ -102,6 +107,9 @@ extern range_process_e packet_range_process_packet(packet_range_t *range, frame_
/* convert user given string to the internal user specified range representation */
extern void packet_range_convert_str(packet_range_t *range, const gchar *es);
+/* convert user given string to the internal selection specified range representation */
+extern void packet_range_convert_selection_str(packet_range_t *range, const gchar *es);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/ui/qt/capture_file_dialog.cpp b/ui/qt/capture_file_dialog.cpp
index 745f499094..95bb78e335 100644
--- a/ui/qt/capture_file_dialog.cpp
+++ b/ui/qt/capture_file_dialog.cpp
@@ -292,10 +292,15 @@ check_savability_t CaptureFileDialog::saveAs(QString &file_name, bool must_suppo
return CANCELLED;
}
-check_savability_t CaptureFileDialog::exportSelectedPackets(QString &file_name, packet_range_t *range) {
+check_savability_t CaptureFileDialog::exportSelectedPackets(QString &file_name, packet_range_t *range, QString selRange) {
GString *fname = g_string_new(file_name.toUtf8().constData());
gboolean wespf_status;
+ if ( selRange.length() > 0 )
+ {
+ packet_range_convert_selection_str(range, selRange.toUtf8().constData());
+ }
+
wespf_status = win32_export_specified_packets_file((HWND)parentWidget()->effectiveWinId(), cap_file_, fname, &file_type_, &compression_type_, range);
file_name = fname->str;
@@ -643,8 +648,8 @@ void CaptureFileDialog::addGzipControls(QVBoxLayout &v_box) {
}
-void CaptureFileDialog::addRangeControls(QVBoxLayout &v_box, packet_range_t *range) {
- packet_range_group_box_.initRange(range);
+void CaptureFileDialog::addRangeControls(QVBoxLayout &v_box, packet_range_t *range, QString selRange) {
+ packet_range_group_box_.initRange(range, selRange);
v_box.addWidget(&packet_range_group_box_, 0, Qt::AlignTop);
}
@@ -720,7 +725,7 @@ check_savability_t CaptureFileDialog::saveAs(QString &file_name, bool must_suppo
return CANCELLED;
}
-check_savability_t CaptureFileDialog::exportSelectedPackets(QString &file_name, packet_range_t *range) {
+check_savability_t CaptureFileDialog::exportSelectedPackets(QString &file_name, packet_range_t *range, QString selRange) {
QDialogButtonBox *button_box;
setWindowTitle(wsApp->windowTitleString(tr("Export Specified Packets")));
@@ -729,7 +734,7 @@ check_savability_t CaptureFileDialog::exportSelectedPackets(QString &file_name,
setAcceptMode(QFileDialog::AcceptSave);
setLabelText(FileType, tr("Export as:"));
- addRangeControls(left_v_box_, range);
+ addRangeControls(left_v_box_, range, selRange);
addGzipControls(right_v_box_);
button_box = addHelpButton(HELP_EXPORT_FILE_DIALOG);
diff --git a/ui/qt/capture_file_dialog.h b/ui/qt/capture_file_dialog.h
index ac8e890347..92cb3f47cf 100644
--- a/ui/qt/capture_file_dialog.h
+++ b/ui/qt/capture_file_dialog.h
@@ -103,7 +103,7 @@ private:
QHash<QString, QStringList> type_suffixes_;
void addGzipControls(QVBoxLayout &v_box);
- void addRangeControls(QVBoxLayout &v_box, packet_range_t *range);
+ void addRangeControls(QVBoxLayout &v_box, packet_range_t *range, QString selRange = QString());
QDialogButtonBox *addHelpButton(topic_action_e help_topic);
QStringList buildFileSaveAsTypeList(bool must_support_comments);
@@ -132,7 +132,7 @@ public slots:
int exec() Q_DECL_OVERRIDE;
int open(QString &file_name, unsigned int &type);
check_savability_t saveAs(QString &file_name, bool must_support_comments);
- check_savability_t exportSelectedPackets(QString &file_name, packet_range_t *range);
+ check_savability_t exportSelectedPackets(QString &file_name, packet_range_t *range, QString selRange = QString());
int merge(QString &file_name);
private slots:
diff --git a/ui/qt/export_dissection_dialog.cpp b/ui/qt/export_dissection_dialog.cpp
index e0afdfbe94..507d4c75e5 100644
--- a/ui/qt/export_dissection_dialog.cpp
+++ b/ui/qt/export_dissection_dialog.cpp
@@ -46,7 +46,7 @@ static const QStringList export_extensions = QStringList()
#endif
-ExportDissectionDialog::ExportDissectionDialog(QWidget *parent, capture_file *cap_file, export_type_e export_type):
+ExportDissectionDialog::ExportDissectionDialog(QWidget *parent, capture_file *cap_file, export_type_e export_type, QString selRange):
QFileDialog(parent),
export_type_(export_type),
cap_file_(cap_file)
@@ -119,7 +119,7 @@ ExportDissectionDialog::ExportDissectionDialog(QWidget *parent, capture_file *ca
/* Default to displayed packets */
print_args_.range.process_filtered = TRUE;
- packet_range_group_box_.initRange(&print_args_.range);
+ packet_range_group_box_.initRange(&print_args_.range, selRange);
h_box->addWidget(&packet_range_group_box_);
h_box->addWidget(&packet_format_group_box_, 0, Qt::AlignTop);
diff --git a/ui/qt/export_dissection_dialog.h b/ui/qt/export_dissection_dialog.h
index 652d32952a..17f5bea990 100644
--- a/ui/qt/export_dissection_dialog.h
+++ b/ui/qt/export_dissection_dialog.h
@@ -32,7 +32,7 @@ class ExportDissectionDialog : public QFileDialog
Q_OBJECT
public:
- explicit ExportDissectionDialog(QWidget *parent, capture_file *cap_file, export_type_e export_type);
+ explicit ExportDissectionDialog(QWidget *parent, capture_file *cap_file, export_type_e export_type, QString selRange = QString());
~ExportDissectionDialog();
public slots:
diff --git a/ui/qt/main_status_bar.cpp b/ui/qt/main_status_bar.cpp
index 996acee3c1..5ca66d8cf1 100644
--- a/ui/qt/main_status_bar.cpp
+++ b/ui/qt/main_status_bar.cpp
@@ -21,6 +21,7 @@
#include "ui/main_statusbar.h"
#include <ui/qt/utils/qt_ui_utils.h>
+#include <ui/qt/main_window.h>
#include "capture_file.h"
#include "main_status_bar.h"
@@ -373,21 +374,26 @@ void MainStatusBar::showCaptureStatistics()
{
QString packets_str;
+ QList<int> rows;
+ MainWindow * mw = qobject_cast<MainWindow *>(wsApp->mainWindow());
+ if ( mw )
+ rows = mw->selectedRows(true);
+
#ifdef HAVE_LIBPCAP
if (cap_file_) {
/* Do we have any packets? */
if (cs_fixed_ && cs_count_ > 0) {
- if (prefs.gui_qt_show_selected_packet && cap_file_->current_frame) {
+ if (prefs.gui_qt_show_selected_packet && rows.count() == 1) {
packets_str.append(QString(tr("Selected Packet: %1 %2 "))
- .arg(cap_file_->current_frame->num)
+ .arg(rows.at(0))
.arg(UTF8_MIDDLE_DOT));
}
packets_str.append(QString(tr("Packets: %1"))
.arg(cs_count_));
} else if (cs_count_ > 0) {
- if (prefs.gui_qt_show_selected_packet && cap_file_->current_frame) {
+ if (prefs.gui_qt_show_selected_packet && rows.count() == 1) {
packets_str.append(QString(tr("Selected Packet: %1 %2 "))
- .arg(cap_file_->current_frame->num)
+ .arg(rows.at(0))
.arg(UTF8_MIDDLE_DOT));
}
packets_str.append(QString(tr("Packets: %1 %4 Displayed: %2 (%3%)"))
@@ -395,6 +401,12 @@ void MainStatusBar::showCaptureStatistics()
.arg(cap_file_->displayed_count)
.arg((100.0*cap_file_->displayed_count)/cap_file_->count, 0, 'f', 1)
.arg(UTF8_MIDDLE_DOT));
+ if(rows.count() > 1) {
+ packets_str.append(QString(tr(" %1 Selected: %2 (%3%)"))
+ .arg(UTF8_MIDDLE_DOT)
+ .arg(rows.count())
+ .arg((100.0*rows.count())/cap_file_->count, 0, 'f', 1));
+ }
if(cap_file_->marked_count > 0) {
packets_str.append(QString(tr(" %1 Marked: %2 (%3%)"))
.arg(UTF8_MIDDLE_DOT)
diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp
index 1376bdc35f..972e986707 100644
--- a/ui/qt/main_window.cpp
+++ b/ui/qt/main_window.cpp
@@ -206,9 +206,14 @@ static void plugin_if_mainwindow_get_ws_info(GHashTable * data_set)
if (cf) {
ws_info->cf_count = cf->count;
- if (cf->state == FILE_READ_DONE && cf->current_frame) {
- ws_info->cf_framenr = cf->current_frame->num;
- ws_info->frame_passed_dfilter = (cf->current_frame->passed_dfilter == 1);
+ QList<int> rows = gbl_cur_main_window_->selectedRows();
+ frame_data * fdata = NULL;
+ if ( rows.count() > 0 )
+ fdata = gbl_cur_main_window_->frameDataForRow(rows.at(0));
+
+ if (cf->state == FILE_READ_DONE && fdata) {
+ ws_info->cf_framenr = fdata->num;
+ ws_info->frame_passed_dfilter = (fdata->passed_dfilter == 1);
}
else {
ws_info->cf_framenr = 0;
@@ -286,7 +291,6 @@ MainWindow::MainWindow(QWidget *parent) :
, capture_interfaces_dialog_(NULL)
, info_data_()
#endif
- , pdlg_(NULL)
, display_filter_dlg_(NULL)
, capture_filter_dlg_(NULL)
#ifdef _WIN32
@@ -462,6 +466,8 @@ MainWindow::MainWindow(QWidget *parent) :
main_ui_->wirelessTimelineWidget->setPacketList(packet_list_);
connect(packet_list_, SIGNAL(frameSelected(int)),
this, SIGNAL(frameSelected(int)));
+ connect(packet_list_, SIGNAL(framesSelected(QList<int>)),
+ this, SLOT(framesSelected(QList<int>)));
connect(this, SIGNAL(frameSelected(int)),
this, SLOT(setMenusForSelectedPacket()));
@@ -475,8 +481,6 @@ MainWindow::MainWindow(QWidget *parent) :
connect(proto_tree_, SIGNAL(fieldSelected(FieldInformation *)),
this, SIGNAL(fieldSelected(FieldInformation *)));
- connect(this, SIGNAL(fieldSelected(FieldInformation *)),
- proto_tree_, SLOT(selectedFieldChanged(FieldInformation *)));
connect(packet_list_, SIGNAL(fieldSelected(FieldInformation *)),
this, SIGNAL(fieldSelected(FieldInformation *)));
connect(this, SIGNAL(fieldSelected(FieldInformation *)),
@@ -906,7 +910,6 @@ void MainWindow::closeEvent(QCloseEvent *event) {
#ifdef HAVE_LIBPCAP
if (capture_interfaces_dialog_) capture_interfaces_dialog_->close();
#endif
- if (pdlg_) pdlg_->close();
// Make sure we kill any open dumpcap processes.
delete welcome_page_;
@@ -1489,7 +1492,7 @@ void MainWindow::exportSelectedPackets() {
packet_range_t range;
cf_write_status_t status;
gchar *dirname;
- gboolean discard_comments = FALSE;
+ bool discard_comments = false;
if (!capture_file_.capFile())
return;
@@ -1499,13 +1502,20 @@ void MainWindow::exportSelectedPackets() {
range.process_filtered = TRUE;
range.include_dependents = TRUE;
+ QList<int> rows = packet_list_->selectedRows(true);
+
+ QStringList entries;
+ foreach ( int row, rows )
+ entries << QString::number(row);
+ QString selRange = entries.join(",");
+
for (;;) {
CaptureFileDialog esp_dlg(this, capture_file_.capFile());
/* If the file has comments, does the format the user selected
support them? If not, ask the user whether they want to
discard the comments or choose a different format. */
- switch (esp_dlg.exportSelectedPackets(file_name, &range)) {
+ switch (esp_dlg.exportSelectedPackets(file_name, &range, selRange)) {
case SAVE:
/* The file can be saved in the specified format as is;
@@ -1610,7 +1620,14 @@ void MainWindow::exportDissections(export_type_e export_type) {
capture_file *cf = capture_file_.capFile();
g_return_if_fail(cf);
- ExportDissectionDialog *ed_dlg = new ExportDissectionDialog(this, cf, export_type);
+ QList<int> rows = packet_list_->selectedRows(true);
+
+ QStringList entries;
+ foreach ( int row, rows )
+ entries << QString::number(row);
+ QString selRange = entries.join(",");
+
+ ExportDissectionDialog *ed_dlg = new ExportDissectionDialog(this, cf, export_type, selRange);
ed_dlg->setWindowModality(Qt::ApplicationModal);
ed_dlg->setAttribute(Qt::WA_DeleteOnClose);
ed_dlg->show();
@@ -2872,6 +2889,21 @@ void MainWindow::setMwFileName(QString fileName)
return;
}
+QList<int> MainWindow::selectedRows(bool useFrameNum)
+{
+ if ( packet_list_ )
+ return packet_list_->selectedRows(useFrameNum);
+ return QList<int>();
+}
+
+frame_data * MainWindow::frameDataForRow(int row) const
+{
+ if ( packet_list_ )
+ return packet_list_->getFDataForRow(row);
+
+ return Q_NULLPTR;
+}
+
/*
* Editor modelines
*
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index bbe9d90d32..d92a001b3e 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -133,6 +133,9 @@ public:
void insertColumn(QString name, QString abbrev, gint pos = -1);
+ QList<int> selectedRows(bool useFrameNum = false);
+ frame_data * frameDataForRow(int row) const;
+
protected:
virtual bool eventFilter(QObject *obj, QEvent *event);
virtual bool event(QEvent *event);
@@ -158,7 +161,10 @@ private:
CopyAllVisibleSelectedTreeItems,
CopySelectedDescription,
CopySelectedFieldName,
- CopySelectedValue
+ CopySelectedValue,
+ CopyListAsText,
+ CopyListAsCSV,
+ CopyListAsYAML
};
enum FileCloseContext {
@@ -209,7 +215,6 @@ private:
CaptureInterfacesDialog *capture_interfaces_dialog_;
info_data_t info_data_;
#endif
- PrintDialog *pdlg_;
FilterDialog *display_filter_dlg_;
FilterDialog *capture_filter_dlg_;
@@ -320,6 +325,8 @@ public slots:
void showWelcome();
void showCapture();
+ void framesSelected(QList<int>);
+
void setTitlebarForCaptureFile();
void setWSWindowTitle(QString title = QString());
@@ -459,6 +466,9 @@ private slots:
void actionEditCopyTriggered(MainWindow::CopySelected selection_type);
void on_actionCopyAllVisibleItems_triggered();
void on_actionCopyAllVisibleSelectedTreeItems_triggered();
+ void on_actionCopyListAsText_triggered();
+ void on_actionCopyListAsCSV_triggered();
+ void on_actionCopyListAsYAML_triggered();
void on_actionEditCopyDescription_triggered();
void on_actionEditCopyFieldName_triggered();
void on_actionEditCopyValue_triggered();
diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui
index 90c11b85fb..6e3a0ffbbb 100644
--- a/ui/qt/main_window.ui
+++ b/ui/qt/main_window.ui
@@ -619,6 +619,10 @@
<property name="title">
<string>Copy</string>
</property>
+ <addaction name="actionCopyListAsText"/>
+ <addaction name="actionCopyListAsCSV"/>
+ <addaction name="actionCopyListAsYAML"/>
+ <addaction name="separator"/>
<addaction name="actionCopyAllVisibleItems"/>
<addaction name="actionCopyAllVisibleSelectedTreeItems"/>
<addaction name="actionEditCopyDescription"/>
@@ -1305,6 +1309,24 @@
<string notr="true">Ctrl+Alt+Shift+D</string>
</property>
</action>
+ <action name="actionCopyListAsText">
+ <property name="text">
+ <string>As Plain &amp;Text…</string>
+ </property>
+ <property name="shortcut">
+ <string notr="true">Ctrl+C</string>
+ </property>
+ </action>
+ <action name="actionCopyListAsCSV">
+ <property name="text">
+ <string>As &amp;CSV…</string>
+ </property>
+ </action>
+ <action name="actionCopyListAsYAML">
+ <property name="text">
+ <string>As &amp;YAML…</string>
+ </property>
+ </action>
<action name="actionCopyAllVisibleItems">
<property name="text">
<string>All Visible Items</string>
@@ -1407,10 +1429,10 @@
</action>
<action name="actionEditMarkPacket">
<property name="text">
- <string>&amp;Mark/Unmark Packet</string>
+ <string>&amp;Mark/Unmark Packet(s)</string>
</property>
<property name="toolTip">
- <string>Mark or unmark this packet</string>
+ <string>Mark or unmark each selected packet</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+M</string>
@@ -1462,10 +1484,10 @@
</action>
<action name="actionEditIgnorePacket">
<property name="text">
- <string>&amp;Ignore/Unignore Packet</string>
+ <string>&amp;Ignore/Unignore Packet(s)</string>
</property>
<property name="toolTip">
- <string>Ignore or unignore this packet</string>
+ <string>Ignore or unignore each selected packet</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+D</string>
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index a4c6784956..d843f84037 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -1130,6 +1130,7 @@ void MainWindow::setMenusForSelectedPacket()
bool have_frames = false;
/* A frame is selected */
bool frame_selected = false;
+ bool multi_selection = false;
/* A visible packet comes after this one in the selection history */
bool next_selection_history = false;
/* A visible packet comes before this one in the selection history */
@@ -1159,20 +1160,31 @@ void MainWindow::setMenusForSelectedPacket()
<< main_ui_->actionViewColorizeConversation9 << main_ui_->actionViewColorizeConversation10;
if (capture_file_.capFile()) {
- frame_selected = capture_file_.capFile()->current_frame != NULL;
+
+ QList<int> rows = selectedRows();
+ frame_data * current_frame = 0;
+ if ( rows.count() > 0 )
+ current_frame = frameDataForRow(rows.at(0));
+
+ frame_selected = rows.count() == 1;
+ if ( packet_list_->multiSelectActive() )
+ {
+ frame_selected = false;
+ multi_selection = true;
+ }
next_selection_history = packet_list_->haveNextHistory();
previous_selection_history = packet_list_->havePreviousHistory();
have_frames = capture_file_.capFile()->count > 0;
have_marked = capture_file_.capFile()->marked_count > 0;
- another_is_marked = have_marked &&
- !(capture_file_.capFile()->marked_count == 1 && frame_selected && capture_file_.capFile()->current_frame->marked);
+ another_is_marked = have_marked && rows.count() <= 1 &&
+ !(capture_file_.capFile()->marked_count == 1 && frame_selected && current_frame->marked);
have_filtered = capture_file_.capFile()->displayed_count > 0 && capture_file_.capFile()->displayed_count != capture_file_.capFile()->count;
have_ignored = capture_file_.capFile()->ignored_count > 0;
have_time_ref = capture_file_.capFile()->ref_time_count > 0;
- another_is_time_ref = have_time_ref &&
- !(capture_file_.capFile()->ref_time_count == 1 && frame_selected && capture_file_.capFile()->current_frame->ref_time);
+ another_is_time_ref = have_time_ref && rows.count() <= 1 &&
+ !(capture_file_.capFile()->ref_time_count == 1 && frame_selected && current_frame->ref_time);
- if (capture_file_.capFile()->edt)
+ if (capture_file_.capFile()->edt && ! multi_selection)
{
proto_get_frame_protocols(capture_file_.capFile()->edt->pi.layers,
&is_ip, &is_tcp, &is_udp, &is_sctp,
@@ -1183,7 +1195,14 @@ void MainWindow::setMenusForSelectedPacket()
}
}
- main_ui_->actionEditMarkPacket->setEnabled(frame_selected);
+ main_ui_->actionEditMarkPacket->setText(tr("&Mark/Unmark Packet(s)", "", selectedRows().count()));
+ main_ui_->actionEditIgnorePacket->setText(tr("&Ignore/Unignore Packet(s)", "", selectedRows().count()));
+
+ main_ui_->actionCopyListAsText->setEnabled(selectedRows().count() > 0);
+ main_ui_->actionCopyListAsCSV->setEnabled(selectedRows().count() > 0);
+ main_ui_->actionCopyListAsYAML->setEnabled(selectedRows().count() > 0);
+
+ main_ui_->actionEditMarkPacket->setEnabled(frame_selected || multi_selection);
main_ui_->actionEditMarkAllDisplayed->setEnabled(have_frames);
/* Unlike un-ignore, do not allow unmark of all frames when no frames are displayed */
main_ui_->actionEditUnmarkAllDisplayed->setEnabled(have_marked);
@@ -1193,7 +1212,7 @@ void MainWindow::setMenusForSelectedPacket()
main_ui_->actionEditPacketComment->setEnabled(frame_selected && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET));
main_ui_->actionDeleteAllPacketComments->setEnabled((capture_file_.capFile() != NULL) && wtap_dump_can_write(capture_file_.capFile()->linktypes, WTAP_COMMENT_PER_PACKET));
- main_ui_->actionEditIgnorePacket->setEnabled(frame_selected);
+ main_ui_->actionEditIgnorePacket->setEnabled(frame_selected || multi_selection);
main_ui_->actionEditIgnoreAllDisplayed->setEnabled(have_filtered);
/* Allow un-ignore of all frames even with no frames currently displayed */
main_ui_->actionEditUnignoreAllDisplayed->setEnabled(have_ignored);
@@ -1313,7 +1332,7 @@ void MainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) {
// Always enable / disable the following items.
main_ui_->actionFileExportPacketBytes->setEnabled(have_field_info);
- main_ui_->actionCopyAllVisibleItems->setEnabled(capture_file_.capFile() != NULL);
+ main_ui_->actionCopyAllVisibleItems->setEnabled(capture_file_.capFile() != NULL && ! packet_list_->multiSelectActive());
main_ui_->actionCopyAllVisibleSelectedTreeItems->setEnabled(can_match_selected);
main_ui_->actionEditCopyDescription->setEnabled(can_match_selected);
main_ui_->actionEditCopyFieldName->setEnabled(can_match_selected);
@@ -1874,15 +1893,14 @@ void MainWindow::on_actionFilePrint_triggered()
capture_file *cf = capture_file_.capFile();
g_return_if_fail(cf);
- if (!pdlg_)
- {
- pdlg_ = new PrintDialog(this, cf);
- }
- else
- {
- pdlg_->cap_file_ = cf;
- }
+ QList<int> rows = packet_list_->selectedRows(true);
+
+ QStringList entries;
+ foreach ( int row, rows )
+ entries << QString::number(row);
+ QString selRange = entries.join(",");
+ PrintDialog * pdlg_ = new PrintDialog(this, cf, selRange);
pdlg_->setWindowModality(Qt::ApplicationModal);
pdlg_->show();
}
@@ -1926,6 +1944,32 @@ void MainWindow::actionEditCopyTriggered(MainWindow::CopySelected selection_type
clip = proto_tree_->toString(proto_tree_->selectionModel()->selectedIndexes().first());
}
break;
+ case CopyListAsText:
+ case CopyListAsCSV:
+ case CopyListAsYAML:
+ if ( packet_list_->selectedRows().count() > 0 )
+ {
+ QList<int> rows = packet_list_->selectedRows();
+ QStringList content;
+ foreach ( int row, rows )
+ {
+ QModelIndex idx = packet_list_->model()->index(row, 0);
+ if ( ! idx.isValid() )
+ continue;
+
+ PacketList::SummaryCopyType copyType = PacketList::CopyAsText;
+ if ( selection_type == CopyListAsCSV )
+ copyType = PacketList::CopyAsCSV;
+ else if ( selection_type == CopyListAsYAML )
+ copyType = PacketList::CopyAsYAML;
+ QString entry = packet_list_->createSummaryText(idx, copyType);
+ content << entry;
+ }
+
+ if ( content.count() > 0 )
+ clip = content.join("\n");
+ }
+ break;
}
if (clip.length() == 0) {
@@ -1947,6 +1991,21 @@ void MainWindow::on_actionCopyAllVisibleItems_triggered()
actionEditCopyTriggered(CopyAllVisibleItems);
}
+void MainWindow::on_actionCopyListAsText_triggered()
+{
+ actionEditCopyTriggered(CopyListAsText);
+}
+
+void MainWindow::on_actionCopyListAsCSV_triggered()
+{
+ actionEditCopyTriggered(CopyListAsCSV);
+}
+
+void MainWindow::on_actionCopyListAsYAML_triggered()
+{
+ actionEditCopyTriggered(CopyListAsYAML);
+}
+
void MainWindow::on_actionCopyAllVisibleSelectedTreeItems_triggered()
{
actionEditCopyTriggered(CopyAllVisibleSelectedTreeItems);
@@ -2104,8 +2163,16 @@ void MainWindow::editTimeShiftFinished(int)
void MainWindow::on_actionEditPacketComment_triggered()
{
+ QList<int> rows = selectedRows();
+ if ( rows.count() != 1 )
+ return;
+
+ frame_data * fdata = frameDataForRow(rows.at(0));
+ if ( ! fdata )
+ return;
+
PacketCommentDialog* pc_dialog;
- pc_dialog = new PacketCommentDialog(capture_file_.capFile()->current_frame->num, this, packet_list_->packetComment());
+ pc_dialog = new PacketCommentDialog(fdata->num, this, packet_list_->packetComment());
connect(pc_dialog, &QDialog::finished, std::bind(&MainWindow::editPacketCommentFinished, this, pc_dialog, std::placeholders::_1));
pc_dialog->setWindowModality(Qt::ApplicationModal);
pc_dialog->setAttribute(Qt::WA_DeleteOnClose);
@@ -2391,7 +2458,7 @@ void MainWindow::colorizeConversation(bool create_rule)
QAction *colorize_action = qobject_cast<QAction *>(sender());
if (!colorize_action) return;
- if (capture_file_.capFile() && capture_file_.capFile()->current_frame) {
+ if (capture_file_.capFile() && selectedRows().count() > 0) {
packet_info *pi = capture_file_.packetInfo();
guint8 cc_num = colorize_action->data().toUInt();
gchar *filter = conversation_filter_from_packet(pi);
@@ -2499,7 +2566,7 @@ void MainWindow::on_actionViewResizeColumns_triggered()
void MainWindow::openPacketDialog(bool from_reference)
{
- frame_data * fdata;
+ frame_data * fdata = Q_NULLPTR;
/* Find the frame for which we're popping up a dialog */
if (from_reference) {
@@ -2508,9 +2575,10 @@ void MainWindow::openPacketDialog(bool from_reference)
return;
fdata = frame_data_sequence_find(capture_file_.capFile()->provider.frames, framenum);
- } else {
- fdata = capture_file_.capFile()->current_frame;
- }
+ } else if ( selectedRows().count() == 1 ) {
+ fdata = frameDataForRow(selectedRows().at(0));
+ } else if ( selectedRows().count() > 1 )
+ return;
/* If we have a frame, pop up the dialog */
if (fdata) {
@@ -3859,6 +3927,11 @@ void MainWindow::activatePluginIFToolbar(bool)
}
}
+void MainWindow::framesSelected(QList<int> /* frames */)
+{
+ setMenusForSelectedPacket();
+}
+
#ifdef _MSC_VER
#pragma warning(pop)
#endif
diff --git a/ui/qt/models/packet_list_model.cpp b/ui/qt/models/packet_list_model.cpp
index 1b9e29d0de..7eff718d59 100644
--- a/ui/qt/models/packet_list_model.cpp
+++ b/ui/qt/models/packet_list_model.cpp
@@ -214,22 +214,33 @@ void PacketListModel::resetColorized()
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
}
-void PacketListModel::toggleFrameMark(const QModelIndex &fm_index)
+void PacketListModel::toggleFrameMark(const QModelIndexList &indeces)
{
- if (!cap_file_ || !fm_index.isValid()) return;
+ if (!cap_file_ || indeces.count() <= 0)
+ return;
- PacketListRecord *record = static_cast<PacketListRecord*>(fm_index.internalPointer());
- if (!record) return;
+ int sectionMax = columnCount() - 1;
- frame_data *fdata = record->frameData();
- if (!fdata) return;
+ foreach (QModelIndex index, indeces) {
+ if (! index.isValid())
+ continue;
- if (fdata->marked)
- cf_unmark_frame(cap_file_, fdata);
- else
- cf_mark_frame(cap_file_, fdata);
+ PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
+ if (!record)
+ continue;
- emit dataChanged(fm_index, fm_index);
+ frame_data *fdata = record->frameData();
+ if (!fdata)
+ continue;
+
+ if (fdata->marked)
+ cf_unmark_frame(cap_file_, fdata);
+ else
+ cf_mark_frame(cap_file_, fdata);
+
+ dataChanged(index.sibling(index.row(), 0), index.sibling(index.row(), sectionMax),
+ QVector<int>() << Qt::BackgroundRole << Qt::ForegroundRole);
+ }
}
void PacketListModel::setDisplayedFrameMark(gboolean set)
@@ -244,20 +255,33 @@ void PacketListModel::setDisplayedFrameMark(gboolean set)
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
}
-void PacketListModel::toggleFrameIgnore(const QModelIndex &i_index)
+void PacketListModel::toggleFrameIgnore(const QModelIndexList &indeces)
{
- if (!cap_file_ || !i_index.isValid()) return;
+ if (!cap_file_ || indeces.count() <= 0)
+ return;
- PacketListRecord *record = static_cast<PacketListRecord*>(i_index.internalPointer());
- if (!record) return;
+ int sectionMax = columnCount() - 1;
- frame_data *fdata = record->frameData();
- if (!fdata) return;
+ foreach (QModelIndex index, indeces) {
+ if (! index.isValid())
+ continue;
+
+ PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
+ if (!record)
+ continue;
- if (fdata->ignored)
- cf_unignore_frame(cap_file_, fdata);
- else
- cf_ignore_frame(cap_file_, fdata);
+ frame_data *fdata = record->frameData();
+ if (!fdata)
+ continue;
+
+ if (fdata->ignored)
+ cf_unignore_frame(cap_file_, fdata);
+ else
+ cf_ignore_frame(cap_file_, fdata);
+
+ dataChanged(index.sibling(index.row(), 0), index.sibling(index.row(), sectionMax),
+ QVector<int>() << Qt::BackgroundRole << Qt::ForegroundRole << Qt::DisplayRole);
+ }
}
void PacketListModel::setDisplayedFrameIgnore(gboolean set)
diff --git a/ui/qt/models/packet_list_model.h b/ui/qt/models/packet_list_model.h
index b12e17cbbc..53f3b908c5 100644
--- a/ui/qt/models/packet_list_model.h
+++ b/ui/qt/models/packet_list_model.h
@@ -60,9 +60,9 @@ public:
*/
void resetColumns();
void resetColorized();
- void toggleFrameMark(const QModelIndex &fm_index);
+ void toggleFrameMark(const QModelIndexList &indeces);
void setDisplayedFrameMark(gboolean set);
- void toggleFrameIgnore(const QModelIndex &i_index);
+ void toggleFrameIgnore(const QModelIndexList &indeces);
void setDisplayedFrameIgnore(gboolean set);
void toggleFrameRefTime(const QModelIndex &rt_index);
void unsetAllFrameRefTime();
diff --git a/ui/qt/models/related_packet_delegate.cpp b/ui/qt/models/related_packet_delegate.cpp
index 89bae07941..72784ea9be 100644
--- a/ui/qt/models/related_packet_delegate.cpp
+++ b/ui/qt/models/related_packet_delegate.cpp
@@ -12,6 +12,9 @@
#include <ui/qt/utils/color_utils.h>
+#include <ui/qt/main_window.h>
+#include <ui/qt/wireshark_application.h>
+
#include <QApplication>
#include <QPainter>
@@ -37,6 +40,18 @@ RelatedPacketDelegate::RelatedPacketDelegate(QWidget *parent) :
void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
+
+ /* This prevents the drawing of related objects, if multiple lines are being selected */
+ if ( wsApp && wsApp->mainWindow() )
+ {
+ MainWindow * mw = qobject_cast<MainWindow *>(wsApp->mainWindow());
+ if ( mw && mw->selectedRows().count() > 1 )
+ {
+ QStyledItemDelegate::paint(painter, option, index);
+ return;
+ }
+ }
+
QStyleOptionViewItem option_vi = option;
QStyledItemDelegate::initStyleOption(&option_vi, index);
int em_w = option_vi.fontMetrics.height();
@@ -202,7 +217,16 @@ void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem
}
QSize RelatedPacketDelegate::sizeHint(const QStyleOptionViewItem &option,
- const QModelIndex &index) const {
+ const QModelIndex &index) const
+{
+ /* This prevents the sizeHint for the delegate, if multiple lines are being selected */
+ if ( wsApp && wsApp->mainWindow() )
+ {
+ MainWindow * mw = qobject_cast<MainWindow *>(wsApp->mainWindow());
+ if ( mw && mw->selectedRows().count() > 1 )
+ return QStyledItemDelegate::sizeHint(option, index);
+ }
+
return QSize(option.fontMetrics.height() + QStyledItemDelegate::sizeHint(option, index).width(),
QStyledItemDelegate::sizeHint(option, index).height());
}
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp
index ad7c44d984..64c0266f7d 100644
--- a/ui/qt/packet_list.cpp
+++ b/ui/qt/packet_list.cpp
@@ -205,12 +205,6 @@ packet_list_recent_write_all(FILE *rf) {
#define MIN_COL_WIDTH_STR "MMMMMM"
-enum copy_summary_type {
- copy_summary_text_,
- copy_summary_csv_,
- copy_summary_yaml_
-};
-
PacketList::PacketList(QWidget *parent) :
QTreeView(parent),
proto_tree_(NULL),
@@ -247,6 +241,8 @@ PacketList::PacketList(QWidget *parent) :
header()->setFirstSectionMovable(true);
#endif
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
// Shrink down to a small but nonzero size in the main splitter.
int one_em = fontMetrics().height();
setMinimumSize(one_em, one_em);
@@ -390,6 +386,48 @@ void PacketList::setProtoTree (ProtoTree *proto_tree) {
&related_packet_delegate_, SLOT(addRelatedFrame(int,ft_framenum_type_t)));
}
+bool PacketList::multiSelectActive()
+{
+ return selectedRows().count() > 1 ? true : false;
+}
+
+QList<int> PacketList::selectedRows(bool useFrameNum)
+{
+ QList<int> rows;
+ if ( selectionModel() && selectionModel()->selectedIndexes().count() > 0 )
+ {
+ foreach ( QModelIndex idx, selectionModel()->selectedIndexes() )
+ {
+ if ( idx.isValid() )
+ {
+ if ( ! useFrameNum && ! rows.contains(idx.row()) )
+ rows << idx.row();
+ else if ( useFrameNum )
+ {
+ frame_data * frame = getFDataForRow(idx.row());
+ if ( frame && ! rows.contains(frame->num) )
+ rows << frame->num;
+ }
+ }
+ }
+
+ std::sort(rows.begin(), rows.end(), std::less<int>());
+ }
+ else if ( currentIndex().isValid() )
+ {
+ if ( ! useFrameNum )
+ rows << currentIndex().row();
+ else
+ {
+ frame_data *frame = getFDataForRow(currentIndex().row());
+ if ( frame )
+ rows << frame->num;
+ }
+ }
+
+ return rows;
+}
+
void PacketList::selectionChanged (const QItemSelection & selected, const QItemSelection & deselected)
{
QTreeView::selectionChanged(selected, deselected);
@@ -397,13 +435,46 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS
if (!cap_file_) return;
int row = -1;
+ static bool multiSelect = false;
+
+ if ( selectionModel() )
+ {
+ if ( selectionModel()->selectedRows(0).count() > 1 )
+ {
+ QList<int> rows;
+ foreach ( QModelIndex idx, selectionModel()->selectedRows(0))
+ {
+ if ( idx.isValid() && ! rows.contains(idx.row()) )
+ rows << idx.row();
+ }
+
+ emit frameSelected(-1);
+ emit framesSelected(rows);
+ emit fieldSelected(0);
+ cf_unselect_packet(cap_file_);
+
+ /* We have to repaint the content while changing state, as some delegates react to multi-select */
+ if ( ! multiSelect )
+ {
+ related_packet_delegate_.clear();
+ viewport()->update();
+ }
+
+ multiSelect = true;
+
+ return;
+ }
+ else if ( selectionModel()->selectedIndexes().count() > 0 && selectionModel()->selectedIndexes().at(0).isValid() )
+ {
+ multiSelect = false;
+ row = selectionModel()->selectedIndexes().at(0).row();
+ }
+ }
- if (selected.isEmpty()) {
+ if ( row < 0 )
cf_unselect_packet(cap_file_);
- } else {
- row = selected.first().top();
+ else
cf_select_packet(cap_file_, row);
- }
if (!in_history_ && cap_file_->current_frame) {
cur_history_++;
@@ -416,6 +487,7 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS
if (proto_tree_) proto_tree_->clear();
emit frameSelected(row);
+ emit framesSelected(QList<int>() << row);
if (!cap_file_->edt) {
viewport()->update();
@@ -489,6 +561,10 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
proto_prefs_menu_.setModule(module_name);
QModelIndex ctxIndex = indexAt(event->pos());
+
+ if ( selectionModel() && selectionModel()->selectedRows(0).count() > 1 )
+ selectionModel()->select(ctxIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
+
// frameData will be owned by one of the submenus, see below.
FrameInformation * frameData =
new FrameInformation(new CaptureFile(this, cap_file_), packet_list_model_->getRowFdata(ctxIndex.row()));
@@ -555,13 +631,13 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
ctx_menu->addMenu(submenu);
QAction * action = submenu->addAction(tr("Summary as Text"));
- action->setData(copy_summary_text_);
+ action->setData(CopyAsText);
connect(action, SIGNAL(triggered()), this, SLOT(copySummary()));
action = submenu->addAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as CSV"));
- action->setData(copy_summary_csv_);
+ action->setData(CopyAsCSV);
connect(action, SIGNAL(triggered()), this, SLOT(copySummary()));
action = submenu->addAction(tr(UTF8_HORIZONTAL_ELLIPSIS "as YAML"));
- action->setData(copy_summary_yaml_);
+ action->setData(CopyAsYAML);
connect(action, SIGNAL(triggered()), this, SLOT(copySummary()));
submenu->addSeparator();
@@ -584,9 +660,9 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
// Set menu sensitivity for the current column and set action data.
if ( frameData )
- emit frameSelected(frameData->frameNum());
+ emit framesSelected(QList<int>() << frameData->frameNum());
else
- emit frameSelected(-1);
+ emit framesSelected(QList<int>());
ctx_menu->exec(event->globalPos());
}
@@ -653,7 +729,7 @@ void PacketList::mousePressEvent (QMouseEvent *event)
bool midButton = ( event->buttons() & Qt::MidButton ) == Qt::MidButton;
if (midButton && cap_file_ && packet_list_model_)
{
- packet_list_model_->toggleFrameMark(curIndex);
+ packet_list_model_->toggleFrameMark(QModelIndexList() << curIndex);
create_far_overlay_ = true;
packets_bar_update();
}
@@ -675,7 +751,24 @@ void PacketList::mouseMoveEvent (QMouseEvent *event)
QWidget * content = nullptr;
QString filter = getFilterFromRowAndColumn(curIndex);
- if ( ! filter.isEmpty() )
+ QList<int> rows = selectedRows();
+ if ( rows.count() > 1 )
+ {
+ QStringList content;
+ foreach ( int row, rows )
+ {
+ QModelIndex idx = model()->index(row, 0);
+ if ( ! idx.isValid() )
+ continue;
+
+ QString entry = createSummaryText(idx, CopyAsText);
+ content << entry;
+ }
+
+ if ( content.count() > 0 )
+ mimeData->setText(content.join("\n"));
+ }
+ else if ( ! filter.isEmpty() )
{
QString abbrev;
QString name = model()->headerData(curIndex.column(), header()->orientation()).toString();
@@ -696,7 +789,6 @@ void PacketList::mouseMoveEvent (QMouseEvent *event)
filterData["filter"] = filter;
filterData["name"] = abbrev;
filterData["description"] = name;
- QMimeData * mimeData = new QMimeData();
mimeData->setData(WiresharkMimeData::DisplayFilterMimeType, QJsonDocument(filterData).toJson());
content = new DragLabel(QString("%1\n%2").arg(name, abbrev), this);
@@ -708,7 +800,7 @@ void PacketList::mouseMoveEvent (QMouseEvent *event)
mimeData->setText(text);
}
- if ( mimeData )
+ if ( mimeData->hasText() || mimeData->hasFormat(WiresharkMimeData::DisplayFilterMimeType) )
{
QDrag * drag = new QDrag(this);
drag->setMimeData(mimeData);
@@ -726,6 +818,34 @@ void PacketList::mouseMoveEvent (QMouseEvent *event)
}
}
+void PacketList::keyPressEvent(QKeyEvent *event)
+{
+ QTreeView::keyPressEvent(event);
+ if ( event->matches(QKeySequence::Copy) )
+ {
+ QStringList content;
+ if ( model() && selectionModel() && selectionModel()->selectedRows(0).count() > 0 )
+ {
+ QList<int> rows;
+ foreach(QModelIndex row, selectionModel()->selectedRows(0))
+ rows.append(row.row());
+
+ foreach(int row, rows)
+ {
+ QModelIndex idx = model()->index(row, 0);
+ if ( ! idx.isValid() )
+ continue;
+
+ QString entry = createSummaryText(idx, CopyAsText);
+ content << entry;
+ }
+ }
+
+ if ( content.count() > 0 )
+ wsApp->clipboard()->setText(content.join('\n'), QClipboard::Clipboard);
+ }
+}
+
void PacketList::resizeEvent(QResizeEvent *event)
{
create_near_overlay_ = true;
@@ -1376,7 +1496,24 @@ void PacketList::markFrame()
{
if (!cap_file_ || !packet_list_model_) return;
- packet_list_model_->toggleFrameMark(currentIndex());
+ QModelIndexList frames;
+
+ if ( selectionModel() && selectionModel()->selectedRows(0).count() > 1 )
+ {
+ QList<int> rows;
+ foreach ( QModelIndex idx, selectionModel()->selectedRows(0) )
+ {
+ if ( idx.isValid() && ! rows.contains(idx.row()) )
+ {
+ frames << idx;
+ rows << idx.row();
+ }
+ }
+ }
+ else
+ frames << currentIndex();
+
+ packet_list_model_->toggleFrameMark(frames);
create_far_overlay_ = true;
packets_bar_update();
}
@@ -1394,7 +1531,25 @@ void PacketList::ignoreFrame()
{
if (!cap_file_ || !packet_list_model_) return;
- packet_list_model_->toggleFrameIgnore(currentIndex());
+ QModelIndexList frames;
+
+ if ( selectionModel() && selectionModel()->selectedRows(0).count() > 1 )
+ {
+ QList<int> rows;
+ foreach ( QModelIndex idx, selectionModel()->selectedRows(0) )
+ {
+ if ( idx.isValid() && ! rows.contains(idx.row()) )
+ {
+ frames << idx;
+ rows << idx.row();
+ }
+ }
+ }
+ else
+ frames << currentIndex();
+
+
+ packet_list_model_->toggleFrameIgnore(frames);
create_far_overlay_ = true;
int sb_val = verticalScrollBar()->value(); // Surely there's a better way to keep our position?
setUpdatesEnabled(false);
@@ -1560,19 +1715,13 @@ void PacketList::updateRowHeights(const QModelIndex &ih_index)
}
}
-void PacketList::copySummary()
+QString PacketList::createSummaryText(QModelIndex idx, SummaryCopyType type)
{
- if (!currentIndex().isValid()) return;
-
- QAction *ca = qobject_cast<QAction*>(sender());
- if (!ca) return;
-
- bool ok = false;
- int copy_type = ca->data().toInt(&ok);
- if (!ok) return;
+ if ( ! idx.isValid() )
+ return "";
QStringList col_parts;
- int row = currentIndex().row();
+ int row = idx.row();
for (int col = 0; col < packet_list_model_->columnCount(); col++) {
if (get_column_visible(col)) {
col_parts << packet_list_model_->data(packet_list_model_->index(row, col), Qt::DisplayRole).toString();
@@ -1580,23 +1729,41 @@ void PacketList::copySummary()
}
QString copy_text;
- switch (copy_type) {
- case copy_summary_csv_:
+ switch (type) {
+ case CopyAsCSV:
copy_text = "\"";
copy_text += col_parts.join("\",\"");
copy_text += "\"";
break;
- case copy_summary_yaml_:
+ case CopyAsYAML:
copy_text = "----\n";
copy_text += QString("# Packet %1 from %2\n").arg(row).arg(cap_file_->filename);
copy_text += "- ";
copy_text += col_parts.join("\n- ");
copy_text += "\n";
break;
- case copy_summary_text_:
+ case CopyAsText:
default:
copy_text = col_parts.join("\t");
}
+
+ return copy_text;
+}
+
+void PacketList::copySummary()
+{
+ if (!currentIndex().isValid()) return;
+
+ QAction *ca = qobject_cast<QAction*>(sender());
+ if (!ca) return;
+
+ QVariant type = ca->data();
+ if ( ! type.canConvert<SummaryCopyType>() )
+ return;
+ SummaryCopyType copy_type = type.value<SummaryCopyType>();
+
+ QString copy_text = createSummaryText(currentIndex(), copy_type);
+
wsApp->clipboard()->setText(copy_text);
}
diff --git a/ui/qt/packet_list.h b/ui/qt/packet_list.h
index 52066eb73e..eaaabbab18 100644
--- a/ui/qt/packet_list.h
+++ b/ui/qt/packet_list.h
@@ -33,6 +33,14 @@ class PacketList : public QTreeView
Q_OBJECT
public:
explicit PacketList(QWidget *parent = 0);
+
+ enum SummaryCopyType {
+ CopyAsText,
+ CopyAsCSV,
+ CopyAsYAML
+ };
+ Q_ENUM(SummaryCopyType)
+
QMenu *conversationMenu() { return &conv_menu_; }
QMenu *colorizeMenu() { return &colorize_menu_; }
void setProtoTree(ProtoTree *proto_tree);
@@ -69,7 +77,13 @@ public:
frame_data * getFDataForRow(int row) const;
+ bool multiSelectActive();
+ QList<int> selectedRows(bool useFrameNum = false);
+
+ QString createSummaryText(QModelIndex idx, SummaryCopyType type);
+
protected:
+
void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected) override;
virtual void contextMenuEvent(QContextMenuEvent *event) override;
void timerEvent(QTimerEvent *event) override;
@@ -78,6 +92,7 @@ protected:
virtual void mouseReleaseEvent (QMouseEvent *event) override;
virtual void mouseMoveEvent (QMouseEvent *event) override;
virtual void resizeEvent(QResizeEvent *event) override;
+ virtual void keyPressEvent(QKeyEvent *event) override;
protected slots:
void rowsInserted(const QModelIndex &parent, int start, int end) override;
@@ -134,6 +149,7 @@ signals:
void editProtocolPreference(struct preference *pref, struct pref_module *module);
void frameSelected(int frameNum);
+ void framesSelected(QList<int>);
void fieldSelected(FieldInformation *);
public slots:
diff --git a/ui/qt/packet_range_group_box.cpp b/ui/qt/packet_range_group_box.cpp
index fff31a6969..8f808a3971 100644
--- a/ui/qt/packet_range_group_box.cpp
+++ b/ui/qt/packet_range_group_box.cpp
@@ -28,7 +28,7 @@ PacketRangeGroupBox::~PacketRangeGroupBox()
delete pr_ui_;
}
-void PacketRangeGroupBox::initRange(packet_range_t *range) {
+void PacketRangeGroupBox::initRange(packet_range_t *range, QString selRange) {
if (!range) return;
range_ = range;
@@ -39,6 +39,9 @@ void PacketRangeGroupBox::initRange(packet_range_t *range) {
pr_ui_->capturedButton->setChecked(true);
}
+ if ( selRange.length() > 0 )
+ packet_range_convert_selection_str(range_, selRange.toUtf8().constData());
+
if (range_->user_range) {
char* tmp_str = range_convert_range(NULL, range_->user_range);
pr_ui_->rangeLineEdit->setText(tmp_str);
@@ -57,7 +60,6 @@ bool PacketRangeGroupBox::isValid() {
void PacketRangeGroupBox::updateCounts() {
SyntaxLineEdit::SyntaxState orig_ss = syntax_state_;
bool displayed_checked = pr_ui_->displayedButton->isChecked();
- int selected_num;
bool can_select;
bool selected_packets;
int ignored_cnt = 0, displayed_ignored_cnt = 0;
@@ -94,12 +96,14 @@ void PacketRangeGroupBox::updateCounts() {
pr_ui_->allDisplayedLabel->setText(QString("%1").arg(label_count));
// Selected / Captured + Displayed
- selected_num = (range_->cf->current_frame) ? range_->cf->current_frame->num : 0;
- can_select = (selected_num != 0);
+ can_select = (range_->selection_range_cnt > 0 || range_->displayed_selection_range_cnt > 0);
if (can_select) {
pr_ui_->selectedButton->setEnabled(true);
pr_ui_->selectedCapturedLabel->setEnabled(!displayed_checked);
pr_ui_->selectedDisplayedLabel->setEnabled(displayed_checked);
+
+ pr_ui_->selectedCapturedLabel->setText(QString::number(range_->selection_range_cnt));
+ pr_ui_->selectedDisplayedLabel->setText(QString::number(range_->displayed_selection_range_cnt));
} else {
if (range_->process == range_process_selected) {
pr_ui_->allButton->setChecked(true);
@@ -107,13 +111,9 @@ void PacketRangeGroupBox::updateCounts() {
pr_ui_->selectedButton->setEnabled(false);
pr_ui_->selectedCapturedLabel->setEnabled(false);
pr_ui_->selectedDisplayedLabel->setEnabled(false);
- }
- if ((range_->remove_ignored && can_select && range_->cf->current_frame->ignored) || selected_num < 1) {
+
pr_ui_->selectedCapturedLabel->setText("0");
pr_ui_->selectedDisplayedLabel->setText("0");
- } else {
- pr_ui_->selectedCapturedLabel->setText("1");
- pr_ui_->selectedDisplayedLabel->setText("1");
}
// Marked / Captured + Displayed
@@ -222,8 +222,8 @@ void PacketRangeGroupBox::updateCounts() {
displayed_ignored_cnt = range_->displayed_ignored_cnt;
break;
case(range_process_selected):
- ignored_cnt = (can_select && range_->cf->current_frame->ignored) ? 1 : 0;
- displayed_ignored_cnt = ignored_cnt;
+ ignored_cnt = range_->ignored_selection_range_cnt;
+ displayed_ignored_cnt = range_->displayed_ignored_selection_range_cnt;
break;
case(range_process_marked):
ignored_cnt = range_->ignored_marked_cnt;
diff --git a/ui/qt/packet_range_group_box.h b/ui/qt/packet_range_group_box.h
index 215f3ee190..12ad025cfa 100644
--- a/ui/qt/packet_range_group_box.h
+++ b/ui/qt/packet_range_group_box.h
@@ -34,7 +34,7 @@ class PacketRangeGroupBox : public QGroupBox
public:
explicit PacketRangeGroupBox(QWidget *parent = 0);
~PacketRangeGroupBox();
- void initRange(packet_range_t *range);
+ void initRange(packet_range_t *range, QString selRange = QString());
bool isValid();
signals:
diff --git a/ui/qt/print_dialog.cpp b/ui/qt/print_dialog.cpp
index 32bf9e8d27..d443407a93 100644
--- a/ui/qt/print_dialog.cpp
+++ b/ui/qt/print_dialog.cpp
@@ -63,7 +63,7 @@ new_page_pd(print_stream_t *self)
} // extern "C"
-PrintDialog::PrintDialog(QWidget *parent, capture_file *cf) :
+PrintDialog::PrintDialog(QWidget *parent, capture_file *cf, QString selRange) :
QDialog(parent),
pd_ui_(new Ui::PrintDialog),
cur_printer_(NULL),
@@ -110,7 +110,7 @@ PrintDialog::PrintDialog(QWidget *parent, capture_file *cf) :
printer_.setDocName(display_basename);
g_free(display_basename);
- pd_ui_->rangeGroupBox->initRange(&print_args_.range);
+ pd_ui_->rangeGroupBox->initRange(&print_args_.range, selRange);
pd_ui_->buttonBox->addButton(print_bt_, QDialogButtonBox::ActionRole);
pd_ui_->buttonBox->addButton(tr("Page &Setup" UTF8_HORIZONTAL_ELLIPSIS), QDialogButtonBox::ResetRole);
@@ -133,8 +133,6 @@ PrintDialog::~PrintDialog()
delete pd_ui_;
}
-// Public
-
gboolean PrintDialog::printHeader()
{
if (!cap_file_ || !cap_file_->filename || !cur_printer_ || !cur_painter_) return FALSE;
diff --git a/ui/qt/print_dialog.h b/ui/qt/print_dialog.h
index 79af98f457..8f821a7541 100644
--- a/ui/qt/print_dialog.h
+++ b/ui/qt/print_dialog.h
@@ -30,17 +30,16 @@ class PrintDialog : public QDialog
Q_OBJECT
public:
- explicit PrintDialog(QWidget *parent = 0, capture_file *cf = NULL);
+ explicit PrintDialog(QWidget *parent = 0, capture_file *cf = NULL, QString selRange = QString());
~PrintDialog();
+
gboolean printHeader();
gboolean printLine(int indent, const char *line);
protected:
- void keyPressEvent(QKeyEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event) override;
private:
- void printPackets(QPrinter *printer = NULL, bool in_preview = false);
-
Ui::PrintDialog *pd_ui_;
QPrinter printer_;
@@ -59,6 +58,8 @@ private:
int page_pos_;
bool in_preview_;
+ void printPackets(QPrinter *printer = NULL, bool in_preview = false);
+
private slots:
void paintPreview(QPrinter *printer);
void checkValidity();
diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp
index 360bed5811..a8fcf2136f 100644
--- a/ui/qt/proto_tree.cpp
+++ b/ui/qt/proto_tree.cpp
@@ -95,6 +95,8 @@ ProtoTree::ProtoTree(QWidget *parent, epan_dissect_t *edt_fixed) :
connect(verticalScrollBar(), SIGNAL(sliderReleased()),
this, SLOT(updateContentWidth()));
+ connect(wsApp, SIGNAL(appInitialized()), this, SLOT(connectToMainWindow()));
+
viewport()->installEventFilter(this);
}
@@ -103,6 +105,17 @@ void ProtoTree::clear() {
updateContentWidth();
}
+void ProtoTree::connectToMainWindow()
+{
+ if ( wsApp->mainWindow() )
+ {
+ connect(wsApp->mainWindow(), SIGNAL(fieldSelected(FieldInformation *)),
+ this, SLOT(selectedFieldChanged(FieldInformation *)));
+ connect(wsApp->mainWindow(), SIGNAL(frameSelected(int)),
+ this, SLOT(selectedFrameChanged(int)));
+ }
+}
+
void ProtoTree::ctxCopyVisibleItems()
{
bool selected_tree = false;
@@ -590,6 +603,12 @@ void ProtoTree::itemDoubleClicked(const QModelIndex &index) {
}
}
+void ProtoTree::selectedFrameChanged(int frameNum)
+{
+ if ( frameNum < 0 )
+ proto_tree_model_->setRootNode(Q_NULLPTR);
+}
+
// Select a field and bring it into view. Intended to be called by external
// components (such as the byte view).
void ProtoTree::selectedFieldChanged(FieldInformation *finfo)
diff --git a/ui/qt/proto_tree.h b/ui/qt/proto_tree.h
index 476f72b727..608ddcb7cb 100644
--- a/ui/qt/proto_tree.h
+++ b/ui/qt/proto_tree.h
@@ -95,6 +95,7 @@ public slots:
void collapseAll();
void itemDoubleClicked(const QModelIndex & index);
void selectedFieldChanged(FieldInformation *);
+ void selectedFrameChanged(int);
protected slots:
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
@@ -109,6 +110,7 @@ protected slots:
private slots:
void updateContentWidth();
+ void connectToMainWindow();
};
#endif // PROTO_TREE_H
diff --git a/ui/qt/wireshark_en.ts b/ui/qt/wireshark_en.ts
index 595e8f8f0f..fe040c29fe 100644
--- a/ui/qt/wireshark_en.ts
+++ b/ui/qt/wireshark_en.ts
@@ -6481,9 +6481,13 @@ For example, use 1 hour to have a new file created every hour on the hour.</sour
<source>Find the previous packet</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source>&amp;Mark/Unmark Packet</source>
- <translation type="unfinished"></translation>
+ <message numerus="yes">
+ <source>&amp;Mark/Unmark Packet(s)</source>
+ <oldsource>&amp;Mark/Unmark Packet</oldsource>
+ <translation type="unfinished">
+ <numerusform>&amp;Mark/Unmark Packet</numerusform>
+ <numerusform>&amp;Mark/Unmark Packets</numerusform>
+ </translation>
</message>
<message>
<source>Mark or unmark this packet</source>
@@ -6517,9 +6521,13 @@ For example, use 1 hour to have a new file created every hour on the hour.</sour
<source>Go to the previous marked packet</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source>&amp;Ignore/Unignore Packet</source>
- <translation type="unfinished"></translation>
+ <message numerus="yes">
+ <source>&amp;Ignore/Unignore Packet(s)</source>
+ <oldsource>&amp;Ignore/Unignore Packet</oldsource>
+ <translation type="unfinished">
+ <numerusform>&amp;Ignore/Unignore Packet</numerusform>
+ <numerusform>&amp;Ignore/Unignore Packets</numerusform>
+ </translation>
</message>
<message>
<source>Ignore or unignore this packet</source>
diff --git a/ui/win32/file_dlg_win32.c b/ui/win32/file_dlg_win32.c
index 6a8a9201e2..a9b579ac6d 100644
--- a/ui/win32/file_dlg_win32.c
+++ b/ui/win32/file_dlg_win32.c
@@ -1606,7 +1606,6 @@ range_update_dynamics(HWND dlg_hwnd, packet_range_t *range) {
HWND cur_ctrl;
gboolean filtered_active = FALSE;
TCHAR static_val[STATIC_LABEL_CHARS];
- gint selected_num;
guint32 ignored_cnt = 0, displayed_ignored_cnt = 0;
guint32 displayed_cnt;
gboolean range_valid = TRUE;
@@ -1639,22 +1638,21 @@ range_update_dynamics(HWND dlg_hwnd, packet_range_t *range) {
SetWindowText(cur_ctrl, static_val);
/* RANGE_SELECT_CURR */
- selected_num = (g_cf->current_frame) ? g_cf->current_frame->num : 0;
cur_ctrl = GetDlgItem(dlg_hwnd, EWFD_SEL_PKT_CAP);
- EnableWindow(cur_ctrl, selected_num && !filtered_active);
- if (range->remove_ignored && g_cf->current_frame && g_cf->current_frame->ignored) {
- StringCchPrintf(static_val, STATIC_LABEL_CHARS, _T("0"));
+ EnableWindow(cur_ctrl, range->selection_range_cnt > 0 && !filtered_active);
+ if (range->remove_ignored) {
+ StringCchPrintf(static_val, STATIC_LABEL_CHARS, _T("%d"), range->selection_range_cnt - range->ignored_selection_range_cnt);
} else {
- StringCchPrintf(static_val, STATIC_LABEL_CHARS, _T("%d"), selected_num ? 1 : 0);
+ StringCchPrintf(static_val, STATIC_LABEL_CHARS, _T("%d"), range->selection_range_cnt);
}
SetWindowText(cur_ctrl, static_val);
cur_ctrl = GetDlgItem(dlg_hwnd, EWFD_SEL_PKT_DISP);
- EnableWindow(cur_ctrl, selected_num && filtered_active);
- if (range->remove_ignored && g_cf->current_frame && g_cf->current_frame->ignored) {
- StringCchPrintf(static_val, STATIC_LABEL_CHARS, _T("0"));
+ EnableWindow(cur_ctrl, range->displayed_selection_range_cnt > 0 && filtered_active);
+ if (range->remove_ignored) {
+ StringCchPrintf(static_val, STATIC_LABEL_CHARS, _T("%d"), range->displayed_selection_range_cnt - range->displayed_ignored_selection_range_cnt);
} else {
- StringCchPrintf(static_val, STATIC_LABEL_CHARS, _T("%d"), selected_num ? 1 : 0);
+ StringCchPrintf(static_val, STATIC_LABEL_CHARS, _T("%d"), range->displayed_selection_range_cnt);
}
SetWindowText(cur_ctrl, static_val);
@@ -1756,8 +1754,8 @@ range_update_dynamics(HWND dlg_hwnd, packet_range_t *range) {
displayed_ignored_cnt = range->displayed_ignored_cnt;
break;
case(range_process_selected):
- ignored_cnt = (g_cf->current_frame && g_cf->current_frame->ignored) ? 1 : 0;
- displayed_ignored_cnt = ignored_cnt;
+ ignored_cnt = range->ignored_selection_range_cnt;
+ displayed_ignored_cnt = range->displayed_ignored_selection_range_cnt;
break;
case(range_process_marked):
ignored_cnt = range->ignored_marked_cnt;