summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gui_gtk.cc16
-rw-r--r--src/gui_main.hh2
-rw-r--r--src/gui_qt.cc9
-rw-r--r--src/monitor-gui.cc46
4 files changed, 71 insertions, 2 deletions
diff --git a/src/gui_gtk.cc b/src/gui_gtk.cc
index 7edd58c..7dd2d42 100644
--- a/src/gui_gtk.cc
+++ b/src/gui_gtk.cc
@@ -625,6 +625,8 @@ public:
return listmodel_ ? list_model_get_model(listmodel_.get()) : nullptr;
}
+ void select_row(size_t row) override;
+
void set_package(std::unique_ptr<AttributedText>&& text) override;
AttributedText* package() const {
@@ -1958,6 +1960,20 @@ void GtkGuiMain::show(GuiWindow* window) {
gtk_window_present(wnd);
}
+void GtkGuiMain::select_row(size_t row) {
+ auto wnd = reinterpret_cast<MainAppWindow*>(window());
+ if (wnd) {
+ auto path = gtk_tree_path_new();
+ gtk_tree_path_append_index(path, row);
+ gtk_tree_selection_select_path(
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(wnd->top_)),
+ path);
+ gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(wnd->top_),
+ path, nullptr, false, .0f, .0f);
+ gtk_tree_path_free(path);
+ }
+}
+
void GtkGuiMain::set_package(std::unique_ptr<AttributedText>&& text) {
package_.swap(text);
auto wnd = reinterpret_cast<MainAppWindow*>(window());
diff --git a/src/gui_main.hh b/src/gui_main.hh
index 1baee2f..d56804c 100644
--- a/src/gui_main.hh
+++ b/src/gui_main.hh
@@ -48,6 +48,8 @@ public:
virtual void set_listmodel(GuiListModel* model) = 0;
virtual GuiListModel* listmodel() const = 0;
+ virtual void select_row(size_t row) = 0;
+
virtual void set_package(std::unique_ptr<AttributedText>&& data) = 0;
virtual bool run(int argc, char** argv) = 0;
diff --git a/src/gui_qt.cc b/src/gui_qt.cc
index 94a00cd..d4bc3d8 100644
--- a/src/gui_qt.cc
+++ b/src/gui_qt.cc
@@ -279,7 +279,8 @@ public:
return flags;
}
- QModelIndex index(int row, int column, const QModelIndex& parent) const override {
+ QModelIndex index(int row, int column,
+ const QModelIndex& parent = QModelIndex()) const override {
if (!parent.isValid()
&& row >= 0 && static_cast<size_t>(row) < model_->rows()
&& column >= 0 && static_cast<size_t>(column) < model_->columns()) {
@@ -450,6 +451,12 @@ public:
return listmodel_ ? listmodel_->model() : nullptr;
}
+ void select_row(size_t row) override {
+ if (!listmodel_ || !top_) return;
+ QTreeView* treeview = static_cast<QTreeView*>(top_);
+ treeview->setCurrentIndex(listmodel_->index(row, 0));
+ }
+
void set_package(std::unique_ptr<AttributedText>&& text) override {
if (text) {
package_ = "<span style=\"font-family: monospace;\">"
diff --git a/src/monitor-gui.cc b/src/monitor-gui.cc
index 9d72608..2b8cf07 100644
--- a/src/monitor-gui.cc
+++ b/src/monitor-gui.cc
@@ -61,6 +61,7 @@ std::string const ACTION_NEW = "new";
std::string const ACTION_OPEN = "open";
std::string const ACTION_SAVE = "save";
std::string const ACTION_SAVE_AS = "save_as";
+std::string const ACTION_JUMP = "jump";
bool valid_hostname(std::string const& host) {
return !host.empty();
@@ -105,6 +106,8 @@ std::string default_cert_bundle() {
class PackageList : public GuiListModel {
public:
+ static const size_t NONE;
+
struct Package {
::Package pkg;
@@ -115,7 +118,10 @@ public:
std::string data;
- Package() {
+ size_t related;
+
+ Package()
+ : related(NONE) {
}
};
@@ -175,6 +181,15 @@ public:
format_host_port(&pkg.to, package.target_host, package.target_port);
format_size(&pkg.size, 0, false);
+ auto related = related_.find(pkg.to);
+ if (related == related_.end()) {
+ related_[pkg.from] = index;
+ } else {
+ pkg.related = related->second;
+ packages_[pkg.related].related = index;
+ related_.erase(related);
+ }
+
notify_added(index, index);
}
@@ -209,6 +224,7 @@ public:
if (last == 0) return;
packages_.clear();
open_.clear();
+ related_.clear();
notify_removed(0, last - 1);
}
@@ -270,12 +286,15 @@ private:
std::unordered_map<uint32_t, size_t> open_;
Observers<Listener*> listeners_;
struct timespec epoch_;
+ std::unordered_map<std::string, size_t> related_;
static const std::string empty_;
};
// static
const PackageList::Package PackageList::EMPTY;
+// static
+const size_t PackageList::NONE = std::numeric_limits<size_t>::max();
// static
const std::string PackageList::empty_;
@@ -655,6 +674,7 @@ public:
statusbar_(GuiStatusBar::create()),
looper_(main_->createLooper()),
has_selection_(false),
+ has_related_(false),
selection_(0),
modified_(false)
{
@@ -703,6 +723,8 @@ public:
edit->add_item(ACTION_COPY_TEXT, "Copy");
edit->add_item(ACTION_COPY_RAW, "Copy binary");
edit->add_separator();
+ edit->add_item(ACTION_JUMP, "Jump to related");
+ edit->add_separator();
edit->add_item(ACTION_CLEAR, "Clear");
#if HAVE_SSL
auto tools = menu_->add_menu("Tools");
@@ -722,6 +744,7 @@ public:
menu_->enable_item(ACTION_COPY_RAW, false);
menu_->enable_item(ACTION_COPY_TEXT, false);
+ menu_->enable_item(ACTION_JUMP, false);
menu_->add_listener(this);
main_->add_listener(this);
@@ -849,6 +872,17 @@ public:
}
auto& pkg = packages_->package(selection_);
main_->add_to_clipboard(pkg.data, "application/octet-stream");
+ } else if (id == ACTION_JUMP) {
+ if (!has_selection_) {
+ assert(false);
+ return;
+ }
+ auto& pkg = packages_->package(selection_);
+ if (pkg.related == PackageList::NONE) {
+ assert(false);
+ return;
+ }
+ main_->select_row(pkg.related);
} else if (id == ACTION_CLEAR) {
packages_->clear();
set_modified(true);
@@ -916,17 +950,22 @@ public:
HexDump::write(text.get(), HexDump::ADDRESS | HexDump::CHARS, pkg.data);
main_->set_package(std::move(text));
+ has_related_ = pkg.related != PackageList::NONE;
+
menu_->enable_item(ACTION_COPY_RAW, true);
menu_->enable_item(ACTION_COPY_TEXT, true);
+ menu_->enable_item(ACTION_JUMP, has_related_);
}
void lost_selection(GuiMain* main) override {
assert(main_.get() == main);
has_selection_ = false;
+ has_related_ = false;
main_->set_package(nullptr);
menu_->enable_item(ACTION_COPY_RAW, false);
menu_->enable_item(ACTION_COPY_TEXT, false);
+ menu_->enable_item(ACTION_JUMP, false);
}
void open(GuiMain*, std::string const& file) override {
@@ -1003,6 +1042,10 @@ public:
assert(monitor == monitor_.get());
packages_->package(package);
set_modified(true);
+ if (has_selection_ && !has_related_) {
+ auto const& pkg = packages_->package(selection_);
+ menu_->enable_item(ACTION_JUMP, pkg.related != PackageList::NONE);
+ }
}
void package_data(Monitor* monitor, uint32_t id,
@@ -1473,6 +1516,7 @@ private:
std::vector<GuiFile::Filter> pem_filter_;
std::vector<GuiFile::Filter> crt_filter_;
bool has_selection_;
+ bool has_related_;
size_t selection_;
std::vector<GuiFile::Filter> file_filter_;
std::string file_;