#include namespace { class CallstackItem { public: CallstackItem() = default; CallstackItem(Glib::ustring callPoint, Glib::ustring stackBase, Glib::ustring symbol, Glib::ustring module, Glib::ustring depth); CallstackItem(Glib::ustring callPoint, const std::vector& children); CallstackItem(const CallstackItem& src) = default; CallstackItem(CallstackItem&& src) noexcept = default; CallstackItem& operator=(const CallstackItem& src) = default; CallstackItem& operator=(CallstackItem&& src) noexcept = default; ~CallstackItem() = default; Glib::ustring callPoint; Glib::ustring stackBase; Glib::ustring symbol; Glib::ustring module; Glib::ustring depth; std::vector m_children; }; // CallstackItem CallstackItem::CallstackItem(Glib::ustring callPoint, Glib::ustring stackBase, Glib::ustring symbol, Glib::ustring module, Glib::ustring depth) : callPoint(std::move(callPoint)), stackBase(std::move(stackBase)), symbol(std::move(symbol)), module(std::move(module)), depth(std::move(depth)) { } CallstackItem::CallstackItem(Glib::ustring callPoint, const std::vector& children) : callPoint(std::move(callPoint)), m_children(children) { } } class CallstackView : public Gtk::ColumnView { protected: class ModelColumns : public Glib::Object { public: std::vector m_children; Glib::ustring callPoint; Glib::ustring stackBase; Glib::ustring symbol; Glib::ustring module; Glib::ustring depth; static Glib::RefPtr create(const CallstackItem& item) { return Glib::make_refptr_for_instance(new ModelColumns(item)); } protected: explicit ModelColumns(const CallstackItem& item) : m_children(item.m_children), callPoint(item.callPoint), stackBase(item.stackBase), symbol(item.symbol), module(item.module), depth(item.depth) { } }; // ModelColumns protected: static Glib::RefPtr create_model( const Glib::RefPtr& item) { auto col = std::dynamic_pointer_cast(item); if (col && col->m_children.empty()) return {}; auto result = Gio::ListStore::create(); const std::vector& children = col ? col->m_children : std::vector(); for (const auto& child : children) result->append(ModelColumns::create(child)); return result; } Glib::RefPtr m_TreeListModel; Glib::RefPtr m_TreeSelection; Glib::RefPtr> _store; public: void append_group(const std::string &name, const std::vector &g) { CallstackItem k(name, g); if(_store) _store->append(ModelColumns::create(k)); } void clear() { _store->remove_all(); } CallstackView (BaseObjectType *cobject, const Glib::RefPtr &refBuilder) : Gtk::ColumnView(cobject) { auto root = create_model({}); m_TreeListModel = Gtk::TreeListModel::create(root, sigc::ptr_fun(&CallstackView::create_model), false, true); m_TreeSelection = Gtk::MultiSelection::create(m_TreeListModel); set_model(m_TreeSelection); { auto factory = Gtk::SignalListItemFactory::create(); factory->signal_setup().connect( sigc::mem_fun(*this, &CallstackView::on_setup_keylabel)); factory->signal_bind().connect( sigc::mem_fun(*this, &CallstackView::on_bind_callPoint)); auto column = Gtk::ColumnViewColumn::create("Call Point", factory); column->set_fixed_width(200); append_column(column); factory = Gtk::SignalListItemFactory::create(); factory->signal_setup().connect( sigc::mem_fun(*this, &CallstackView::on_setup_label)); factory->signal_bind().connect( sigc::mem_fun(*this, &CallstackView::on_bind_stackBase)); column = Gtk::ColumnViewColumn::create("Stack Base", factory); column->set_expand(); append_column(column); factory = Gtk::SignalListItemFactory::create(); factory->signal_setup().connect( sigc::mem_fun(*this, &CallstackView::on_setup_label)); factory->signal_bind().connect( sigc::mem_fun(*this, &CallstackView::on_bind_symbol)); column = Gtk::ColumnViewColumn::create("Symbol", factory); column->set_expand(); append_column(column); factory = Gtk::SignalListItemFactory::create(); factory->signal_setup().connect( sigc::mem_fun(*this, &CallstackView::on_setup_label)); factory->signal_bind().connect( sigc::mem_fun(*this, &CallstackView::on_bind_module)); column = Gtk::ColumnViewColumn::create("Module", factory); column->set_expand(); append_column(column); factory = Gtk::SignalListItemFactory::create(); factory->signal_setup().connect( sigc::mem_fun(*this, &CallstackView::on_setup_label)); factory->signal_bind().connect( sigc::mem_fun(*this, &CallstackView::on_bind_depth)); column = Gtk::ColumnViewColumn::create("Depth", factory); column->set_expand(); append_column(column); } _store = std::dynamic_pointer_cast>(root); } void on_setup_keylabel( const Glib::RefPtr& list_item) { // Each ListItem contains a TreeExpander, which contains a Label. // The Label shows the ModelColumns::m_holiday_name. That's done in on_bind_holiday(). auto expander = Gtk::make_managed(); auto label = Gtk::make_managed(); label->set_halign(Gtk::Align::START); expander->set_child(*label); list_item->set_child(*expander); } void on_setup_label( const Glib::RefPtr& list_item) { // Each ListItem contains a TreeExpander, which contains a Label. // The Label shows the ModelColumns::m_holiday_name. That's done in on_bind_holiday(). auto label = Gtk::make_managed(); label->set_halign(Gtk::Align::START); list_item->set_child(*label); } void on_bind_callPoint( const Glib::RefPtr& list_item) { auto row = std::dynamic_pointer_cast(list_item->get_item()); if (!row) return; auto col = std::dynamic_pointer_cast(row->get_item()); if (!col) return; auto expander = dynamic_cast(list_item->get_child()); if (!expander) return; expander->set_list_row(row); auto label = dynamic_cast(expander->get_child()); if (!label) return; label->set_text(col->callPoint); } void on_bind_stackBase( const Glib::RefPtr& list_item) { auto row = std::dynamic_pointer_cast(list_item->get_item()); if (!row) return; auto label = dynamic_cast(list_item->get_child()); if (!label) return; label->set_visible(!row->is_expandable()); if (row->is_expandable()) return; auto col = std::dynamic_pointer_cast(row->get_item()); if (!col) return; label->set_text(col->stackBase); } void on_bind_symbol( const Glib::RefPtr& list_item) { auto row = std::dynamic_pointer_cast(list_item->get_item()); if (!row) return; auto label = dynamic_cast(list_item->get_child()); if (!label) return; label->set_visible(!row->is_expandable()); if (row->is_expandable()) return; auto col = std::dynamic_pointer_cast(row->get_item()); if (!col) return; label->set_text(col->symbol); } void on_bind_module( const Glib::RefPtr& list_item) { auto row = std::dynamic_pointer_cast(list_item->get_item()); if (!row) return; auto label = dynamic_cast(list_item->get_child()); if (!label) return; label->set_visible(!row->is_expandable()); if (row->is_expandable()) return; auto col = std::dynamic_pointer_cast(row->get_item()); if (!col) return; label->set_text(col->module); } void on_bind_depth( const Glib::RefPtr& list_item) { auto row = std::dynamic_pointer_cast(list_item->get_item()); if (!row) return; auto label = dynamic_cast(list_item->get_child()); if (!label) return; label->set_visible(!row->is_expandable()); if (row->is_expandable()) return; auto col = std::dynamic_pointer_cast(row->get_item()); if (!col) return; label->set_text(col->depth); } };