[nemiver/monitor-variable: 6/6] Contextual menu to add/remove expression to the monitor
- From: Dodji Seketeli <dodji src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nemiver/monitor-variable: 6/6] Contextual menu to add/remove expression to the monitor
- Date: Mon, 28 May 2012 21:58:39 +0000 (UTC)
commit 8f4571137512a3eafade920df2f92ab371d31029
Author: Dodji Seketeli <dodji seketeli org>
Date: Mon May 28 20:13:40 2012 +0200
Contextual menu to add/remove expression to the monitor
* src/persp/dbgperspective/menus/Makefile.am: Add
varsmonitorpopup.xml to the build system.
* src/persp/dbgperspective/menus/varsmonitorpopup.xml: New
description file for the contextual menu.
* src/persp/dbgperspective/nmv-vars-monitor.{cc,h}: Lots of new
stuff.
src/persp/dbgperspective/menus/Makefile.am | 2 +-
.../dbgperspective/menus/varsmonitorpopup.xml | 9 +
src/persp/dbgperspective/nmv-vars-monitor.cc | 348 +++++++++++++++++++-
src/persp/dbgperspective/nmv-vars-monitor.h | 1 +
4 files changed, 358 insertions(+), 2 deletions(-)
---
diff --git a/src/persp/dbgperspective/menus/Makefile.am b/src/persp/dbgperspective/menus/Makefile.am
index a6dc6d8..3580dfd 100644
--- a/src/persp/dbgperspective/menus/Makefile.am
+++ b/src/persp/dbgperspective/menus/Makefile.am
@@ -8,7 +8,7 @@ callstackpopup.xml \
varinspectorpopup.xml \
localvarsinspectorpopup.todelete.xml \
localvarsinspectorpopup.xml \
-terminalmenu.xml
+terminalmenu.xml varsmonitorpopup.xml
menusdir = @NEMIVER_PLUGINS_DIR@/$(PLUGIN_NAME)/menus
menus_DATA = $(menusfiles)
diff --git a/src/persp/dbgperspective/menus/varsmonitorpopup.xml b/src/persp/dbgperspective/menus/varsmonitorpopup.xml
new file mode 100644
index 0000000..09168c1
--- /dev/null
+++ b/src/persp/dbgperspective/menus/varsmonitorpopup.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<ui>
+ <popup name="VarsMonitorPopup">
+ <menuitem action="AddVariableMenuItemAction"
+ name="AddVariableMenuItem"/>
+ <menuitem action="RemoveVariablesMenuItemAction"
+ name="RemoveVariablesMenuItem" />
+ </popup>
+</ui>
diff --git a/src/persp/dbgperspective/nmv-vars-monitor.cc b/src/persp/dbgperspective/nmv-vars-monitor.cc
index d06e524..9018e06 100644
--- a/src/persp/dbgperspective/nmv-vars-monitor.cc
+++ b/src/persp/dbgperspective/nmv-vars-monitor.cc
@@ -30,6 +30,8 @@
#include "nmv-vars-treeview.h"
#include "nmv-variables-utils.h"
#include "nmv-debugger-utils.h"
+#include "nmv-i-workbench.h"
+#include "nmv-var-inspector-dialog.h"
using namespace nemiver::common;
namespace vutils = nemiver::variables_utils2;
@@ -41,6 +43,7 @@ NEMIVER_BEGIN_NAMESPACE (nemiver)
struct VarsMonitor::Priv
{
+ Glib::RefPtr<Gtk::UIManager> ui_manager;
IDebugger &debugger;
IPerspective &perspective;
SafePtr<VarsTreeView> tree_view;
@@ -52,6 +55,9 @@ struct VarsMonitor::Priv
IDebugger::VariableList changed_in_scope_vars_at_prev_stop;
IDebugger::VariableList changed_oo_scope_vars_at_prev_stop;
map<IDebugger::VariableSafePtr, bool> in_scope_vars;
+ vector<Gtk::TreeModel::Path> selected_paths;
+ Glib::RefPtr<Gtk::ActionGroup> action_group;
+ Gtk::Widget *contextual_menu;
IDebugger::Frame saved_frame;
IDebugger::StopReason saved_reason;
bool saved_has_frame;
@@ -63,6 +69,7 @@ struct VarsMonitor::Priv
IPerspective &a_perspective)
: debugger (a_debugger),
perspective (a_perspective),
+ contextual_menu (0),
saved_reason (IDebugger::UNDEFINED_REASON),
saved_has_frame (false),
initialized (false),
@@ -134,12 +141,14 @@ struct VarsMonitor::Priv
initialized = true;
}
+ /// Re-initialize the widget.
void
re_init_widget ()
{
LOG_FUNCTION_SCOPE_NORMAL_DD;
}
+ /// Connect to the graphical
void
connect_to_debugger_signal ()
{
@@ -149,6 +158,7 @@ struct VarsMonitor::Priv
(sigc::mem_fun (*this, &Priv::on_stopped_signal));
}
+ /// Connect slot to signals related to graphical stuff.
void
init_graphical_signals ()
{
@@ -159,13 +169,96 @@ struct VarsMonitor::Priv
tree_view->signal_draw ().connect_notify
(sigc::mem_fun (this, &Priv::on_draw_signal));
+
+ // Schedule the button press signal handler to be run before
+ // the default handler.
+ tree_view->signal_button_press_event ().connect_notify
+ (sigc::mem_fun (this, &Priv::on_button_press_signal));
+
+ Glib::RefPtr<Gtk::TreeSelection> selection =
+ tree_view->get_selection ();
+ selection->set_mode (Gtk::SELECTION_MULTIPLE);
+
+ selection->signal_changed ().connect
+ (sigc::mem_fun (*this,
+ &Priv::on_tree_view_selection_changed_signal));
}
+ /// Initialize actions to be triggered whenever the user clicks on
+ /// menu items that are specific to variable monitoring.
void
init_actions ()
{
+ ui_utils::ActionEntry s_vars_monitor_action_entries [] = {
+ {
+ "RemoveVariablesMenuItemAction",
+ Gtk::Stock::DELETE,
+ _("Remove"),
+ _("Remove selected variables from the monitor"),
+ sigc::mem_fun (*this, &Priv::on_remove_variables_action),
+ ui_utils::ActionEntry::DEFAULT,
+ "",
+ false
+ },
+ {
+ "AddVariableMenuItemAction",
+ Gtk::Stock::ADD,
+ _("New ..."),
+ _("Add a new variable to the monitor"),
+ sigc::mem_fun (*this, &Priv::on_add_variable_action),
+ ui_utils::ActionEntry::DEFAULT,
+ "",
+ false
+ }
+ };
+ action_group =
+ Gtk::ActionGroup::create ("vars-monitor-action-group");
+ action_group->set_sensitive (true);
+ int num_actions =
+ sizeof (s_vars_monitor_action_entries)
+ /
+ sizeof (ui_utils::ActionEntry);
+ ui_utils::add_action_entries_to_action_group
+ (s_vars_monitor_action_entries,
+ num_actions,
+ action_group);
+ get_ui_manager ()->insert_action_group (action_group);
+ }
+
+ /// Return true iff the variable in parameter is currently being
+ /// monitored.
+ ///
+ /// \param a_var the variable to check for.
+ bool
+ variable_monitored (const IDebugger::Variable &a_var) const
+ {
+ IDebugger::VariableList::const_iterator it;
+ for (it = monitored_variables.begin ();
+ it != monitored_variables.end ();
+ ++it) {
+ if (!a_var.internal_name ().empty ()
+ && a_var.internal_name () == (*it)->internal_name ())
+ // Both variables have the same internal name, so they
+ // are equal.
+ return true;
+ else if (!(*it)->needs_unfolding ()
+ && !a_var.needs_unfolding ()) {
+ // Both variables have been unfolded, so we can
+ // compare them by value.
+ if ((*it)->equals_by_value (a_var))
+ return true;
+ } else {
+ if (a_var.name () == a_var.name ())
+ return true;
+ }
+ }
+ return false;
}
+ /// Monitor a new expression (or varibale). In other words, add a
+ /// new variable to the monitor.
+ ///
+ /// \param a_var the variable to monitor.
void
add_variable (const IDebugger::VariableSafePtr a_var)
{
@@ -173,7 +266,7 @@ struct VarsMonitor::Priv
LOG_DD ("a_var: " << a_var->id ());
- if (!a_var)
+ if (!a_var || variable_monitored (*a_var))
return;
monitored_variables.push_back (a_var);
@@ -189,6 +282,9 @@ struct VarsMonitor::Priv
/*a_truncate_type=*/true);
}
+ /// Monitor a list of new variables.
+ ///
+ /// \param a_vars the variables to monitor.
void
add_variables (const IDebugger::VariableList &a_vars)
{
@@ -199,6 +295,9 @@ struct VarsMonitor::Priv
add_variable (*it);
}
+ /// Remove a variable from the monitor.
+ ///
+ /// \param a_var the variable to remove from the monitor.
void
remove_variable (const IDebugger::VariableSafePtr a_var)
{
@@ -409,6 +508,100 @@ struct VarsMonitor::Priv
NEMIVER_CATCH;
}
+ /// Return the UI manager associated with this variable monitor.
+ /// this is for e.g, the contextual menu.
+ Glib::RefPtr<Gtk::UIManager>
+ get_ui_manager ()
+ {
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ if (!ui_manager)
+ ui_manager = Gtk::UIManager::create ();
+ return ui_manager;
+ }
+
+ /// Return the contextual menu for the variable menu. Build it,
+ /// if it is not already built.
+ ///
+ /// \return a widget representing the contextual menu.
+ Gtk::Widget*
+ get_contextual_menu ()
+ {
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ if (!contextual_menu) {
+ string absolute_path;
+ perspective.build_absolute_resource_path
+ (Glib::build_filename ("menus", "varsmonitorpopup.xml"),
+ absolute_path);
+ get_ui_manager ()->add_ui_from_file (absolute_path);
+ get_ui_manager ()->ensure_update ();
+ contextual_menu =
+ get_ui_manager ()->get_widget ("/VarsMonitorPopup");
+ THROW_IF_FAIL (contextual_menu);
+ }
+ return contextual_menu;
+ }
+
+ /// Return true iff a given path pointing at a row of the variable
+ /// monitor is for a row that contains an instance of
+ /// IDebugger::Variable.
+ ///
+ /// \param a_path the path to check for.
+ bool
+ path_points_to_variable (const Gtk::TreeModel::Path &a_path) const
+ {
+ Gtk::TreeModel::iterator it = tree_store->get_iter (a_path);
+ if (it->get_value (vutils::get_variable_columns ().variable))
+ return true;
+ return false;
+ }
+
+ /// Return true iff a row containing an instance of
+ /// IDebugger::Variable has been selected (clicked) by the user.
+ bool
+ variable_is_selected () const
+ {
+ std::vector<Gtk::TreeModel::Path> selected_paths =
+ tree_view->get_selection ()->get_selected_rows ();
+ std::vector<Gtk::TreeModel::Path>::const_iterator it;
+ for (it = selected_paths.begin ();
+ it != selected_paths.end ();
+ ++it)
+ if (path_points_to_variable (*it))
+ return true;
+ return false;
+ }
+
+ /// Update the sensitivity of the items of the contextual menu,
+ /// depending on the set of rows that are currently selected.
+ void
+ update_contextual_menu_sensitivity ()
+ {
+ Glib::RefPtr<Gtk::Action> remove_variable_action =
+ get_ui_manager ()->get_action
+ ("/VarsMonitorPopup/RemoveVariablesMenuItem");
+ THROW_IF_FAIL (remove_variable_action);
+
+ Glib::RefPtr<Gtk::TreeSelection> selection = tree_view->get_selection ();
+ THROW_IF_FAIL (selection);
+
+ remove_variable_action->set_sensitive
+ (variable_is_selected ());
+ }
+
+ /// Pop up the contextual menu of the variable monitor.
+ void
+ popup_contextual_menu (GdkEventButton *a_event)
+ {
+ Gtk::Menu *menu = dynamic_cast<Gtk::Menu*> (get_contextual_menu ());
+ THROW_IF_FAIL (menu);
+
+ update_contextual_menu_sensitivity ();
+
+ menu->popup (a_event->button, a_event->time);
+ }
+
// *********************
// <signal handlers>
// ********************
@@ -541,6 +734,134 @@ struct VarsMonitor::Priv
NEMIVER_CATCH;
}
+ /// Callback function called whenever the user presses button from
+ /// either the keyboard or the mousse.
+ void
+ on_button_press_signal (GdkEventButton *a_event)
+ {
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ NEMIVER_TRY;
+
+ // Right-clicking should pop up a context menu
+ if (a_event->type == GDK_BUTTON_PRESS
+ && a_event->button == 3)
+ popup_contextual_menu (a_event);
+
+ NEMIVER_CATCH;
+ }
+
+ /// Callback called whenever the user clicks on a menu item to
+ /// remove the set of currently selected variables.
+ void
+ on_remove_variables_action ()
+ {
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ NEMIVER_TRY;
+
+ Glib::RefPtr<Gtk::TreeSelection> selection = tree_view->get_selection ();
+ THROW_IF_FAIL (selection);
+
+ std::vector<Gtk::TreeModel::Path> selected_rows =
+ selection->get_selected_rows ();
+
+ std::list<IDebugger::VariableSafePtr> delete_list;
+ for (std::vector<Gtk::TreeModel::Path>::const_iterator it =
+ selected_rows.begin ();
+ it != selected_rows.end ();
+ ++it) {
+ Gtk::TreeModel::iterator i = tree_store->get_iter (*it);
+ IDebugger::VariableSafePtr cur_var =
+ (*i)[vutils::get_variable_columns ().variable];
+ THROW_IF_FAIL (cur_var);
+ delete_list.push_back (cur_var->root ());
+ }
+ for (std::list<IDebugger::VariableSafePtr>::const_iterator it =
+ delete_list.begin ();
+ it != delete_list.end ();
+ ++it) {
+ remove_variable (*it);
+ }
+
+ NEMIVER_CATCH;
+ }
+
+ /// Callback function invoked whenever the user clicks on a menu
+ /// item to monitor a new expression.
+ void
+ on_add_variable_action ()
+ {
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ VarInspectorDialog dialog (debugger, perspective);
+ dialog.expr_monitoring_requested ().connect
+ (sigc::mem_fun (*this,
+ &VarsMonitor::Priv::on_expr_monitoring_requested));
+ dialog.inspector ().var_inspected_signal ().connect
+ (sigc::bind (sigc::mem_fun (*this,
+ &VarsMonitor::Priv::on_expr_inspected),
+ &dialog));
+ dialog.run ();
+ }
+
+ /// Callback function invoked whenever an expression has been been
+ /// inspected. This is usuall triggered when the user clicks on
+ /// the the "inspect" button in the VarInspectorDialog dialog.
+ ///
+ /// \param a_var the expression that got recently inspected
+ ///
+ /// \param a_dialog the dialog this variable monitor belongs to.
+ void
+ on_expr_inspected (const IDebugger::VariableSafePtr a_var,
+ VarInspectorDialog *a_dialog)
+ {
+ if (variable_monitored (*a_var))
+ {
+ a_dialog->functionality_mask
+ (a_dialog->functionality_mask ()
+ & ~VarInspectorDialog::FUNCTIONALITY_EXPR_MONITOR_PICKER);
+ }
+ else
+ {
+ a_dialog->functionality_mask
+ (a_dialog->functionality_mask ()
+ | VarInspectorDialog::FUNCTIONALITY_EXPR_MONITOR_PICKER);
+ }
+ }
+
+ /// Callback function invoked whenever the user clicks on the
+ /// "monitor variable" button in the dialog launched by
+ /// on_add_variable_action above.
+ void
+ on_expr_monitoring_requested (const IDebugger::VariableSafePtr a_var)
+ {
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ add_variable (a_var);
+ }
+
+ /// Callback function invoked whenever the user selects or
+ /// unselects rows of the variable monitor.
+ void
+ on_tree_view_selection_changed_signal ()
+ {
+ LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+ NEMIVER_TRY;
+
+ THROW_IF_FAIL (tree_view);
+ THROW_IF_FAIL (tree_store);
+
+ Glib::RefPtr<Gtk::TreeSelection> selection = tree_view->get_selection ();
+ THROW_IF_FAIL (selection);
+
+ selected_paths =
+ selection->get_selected_rows ();
+
+ NEMIVER_CATCH;
+ }
+
// *********************
// </signal handlers>
// ********************
@@ -557,6 +878,7 @@ VarsMonitor::~VarsMonitor ()
{
}
+/// Return the widget for this type.
Gtk::Widget&
VarsMonitor::widget ()
{
@@ -564,33 +886,57 @@ VarsMonitor::widget ()
return m_priv->get_widget ();
}
+/// Monitor a new variable. IOW, add a new variable to the monitor.
+///
+/// \param a_var the new variable to monitor.
void
VarsMonitor::add_variable (const IDebugger::VariableSafePtr a_var)
{
m_priv->add_variable (a_var);
}
+/// Monitor a list of new variables.
+///
+/// \param a_vars the variables to monitor.
void
VarsMonitor::add_variables (const IDebugger::VariableList &a_vars)
{
m_priv->add_variables (a_vars);
}
+/// Return true iff the given variable is being monitored by this
+/// monitored.
+///
+/// \param a_var the variable to check for.
+bool
+VarsMonitor::variable_monitored (const IDebugger::Variable &a_var) const
+{
+ return m_priv->variable_monitored (a_var);
+}
+
+/// Remove a variable from the monitor.
+///
+/// \param a_var the variable to remove from the monitor.
void
VarsMonitor::remove_variable (const IDebugger::VariableSafePtr a_var)
{
m_priv->remove_variable (a_var);
}
+/// Remove a list of variables from the monitor.
+///
+/// \param a_vars the list of variables to remove.
void
VarsMonitor::remove_variables (const std::list<IDebugger::VariableSafePtr> &a_vars)
{
m_priv->remove_variables (a_vars);
}
+/// Clear the widget.
void
VarsMonitor::re_init_widget ()
{
+ m_priv->re_init_widget ();
}
NEMIVER_END_NAMESPACE (nemiver)
diff --git a/src/persp/dbgperspective/nmv-vars-monitor.h b/src/persp/dbgperspective/nmv-vars-monitor.h
index 44f1962..143b516 100644
--- a/src/persp/dbgperspective/nmv-vars-monitor.h
+++ b/src/persp/dbgperspective/nmv-vars-monitor.h
@@ -57,6 +57,7 @@ class NEMIVER_API VarsMonitor : public nemiver::common::Object {
Gtk::Widget& widget ();
void add_variable (const IDebugger::VariableSafePtr a_var);
void add_variables (const IDebugger::VariableList &a_vars);
+ bool variable_monitored (const IDebugger::Variable &a_var) const;
void remove_variable (const IDebugger::VariableSafePtr a_var);
void remove_variables (const IDebugger::VariableList &a_vars);
void re_init_widget ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]