# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1428759401 -7200
#      Sat Apr 11 15:36:41 2015 +0200
# Node ID 0d22f39e87d003785fda08c26a2d5acec6ee54a2
# Parent  e10ad5214a59c61b7bd68bb3aaf5d4e6f2ad2e5f
Handle uicontextmenu deletion/reset (bug #44801)

*graphics.in.h (base_graphics_opbject::properties): add updater for uicontextmenu property
*graphics.in.h (uicontextmenu::properties::dependent_obj_list): new private
  attribute to store the list of objects that may depend on this uicontextmenu.
*graphics.in.h (uicontextmenu::properties::get_dependent_obj_list (), 
                uicontextmenu::properties::add_dependent_obj ()): new methods

* graphics.cc (base_graphics_opbject::properties::update_uicontextmenu): 
   new method to mark this graphics object as dependent on an 
   uicontextmenu object. 
* graphics.cc (uicontextmenu::~uicontextmenu): reset the "uicontextmenu" 
   property of objects that have this uicontextmenu as current. 
* graphics.cc (handle_property::do_set): let users reset a handle property 
   using empty matrix.
* graphics.cc: add BIST for bug #44801

diff -r e10ad5214a59 -r 0d22f39e87d0 libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Thu Apr 09 16:08:02 2015 +0300
+++ b/libinterp/corefcn/graphics.cc	Sat Apr 11 15:36:41 2015 +0200
@@ -1473,6 +1473,18 @@
 bool
 handle_property::do_set (const octave_value& v)
 {
+  // Users may want to use empty matrix to reset a handle property
+  if (v.is_empty ())
+    {
+      if (! get ().is_empty ())
+        {
+          current_val = graphics_handle ();
+          return true;
+        }
+      else
+        return false;
+    }
+
   double dv = v.double_value ();
 
   if (! error_state)
@@ -3085,6 +3097,21 @@
     obj.update_axis_limits (axis_type, h);
 }
 
+void
+base_properties::update_uicontextmenu (void) const
+{
+  if (uicontextmenu.get ().is_empty ())
+    return;
+  
+  graphics_object obj = gh_manager::get_object (uicontextmenu.get ());
+  if (obj && obj.isa ("uicontextmenu"))
+    {
+      uicontextmenu::properties& props =
+        reinterpret_cast<uicontextmenu::properties&> (obj.get_properties ());
+      props.add_dependent_obj (__myhandle__);
+    }
+}
+
 bool
 base_properties::is_handle_visible (void) const
 {
@@ -8813,6 +8840,51 @@
 
 // ---------------------------------------------------------------------
 
+uicontextmenu::~uicontextmenu (void)
+{ 
+  std::list<graphics_handle> lst = xproperties.get_dependent_obj_list ();
+  std::list<graphics_handle>::const_iterator it;
+  
+  for (it = lst.begin (); it != lst.end (); it++)
+    {
+      graphics_object go = gh_manager::get_object (*it);
+      
+      if (go.valid_object () &&
+          go.get ("uicontextmenu") == xproperties.get___myhandle__ ())
+        go.set ("uicontextmenu", Matrix ());
+    }
+}
+
+
+/*
+## Test deletion/reset of uicontextmenu
+%!test
+%! hf = figure ("visible", "off");
+%! hax = axes ("parent", hf);
+%! unwind_protect
+%!   hctx1 = uicontextmenu ("parent", hf);
+%!   hctx2 = uicontextmenu ("parent", hf);
+%!   set (hf, "uicontextmenu", hctx2);
+%!   set (hax, "uicontextmenu", hctx2);
+%!   assert (get (hf, "uicontextmenu"), hctx2);
+%!   assert (get (hax, "uicontextmenu"), hctx2);
+%!   assert (get (hf, "children"), [hctx2; hctx1; hax]);
+%!   delete (hctx2);
+%!   assert (get (hf, "uicontextmenu"), []);
+%!   assert (get (hax, "uicontextmenu"), []);
+%!   assert (get (hf, "children"), [hctx1; hax]);
+%!   set (hf, "uicontextmenu", hctx1);
+%!   assert (get (hf, "uicontextmenu"), hctx1);
+%!   set (hf, "uicontextmenu", []);
+%!   assert (get (hf, "uicontextmenu"), []);
+%!   assert (get (hf, "children"), [hctx1; hax]);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect;
+ */
+
+// ---------------------------------------------------------------------
+
 octave_value
 uicontrol::properties::get_extent (void) const
 {
diff -r e10ad5214a59 -r 0d22f39e87d0 libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h	Thu Apr 09 16:08:02 2015 +0300
+++ b/libinterp/corefcn/graphics.in.h	Sat Apr 11 15:36:41 2015 +0200
@@ -2595,6 +2595,8 @@
   virtual void update_axis_limits (const std::string& axis_type,
                                    const graphics_handle& h) const;
 
+  virtual void update_uicontextmenu (void) const;
+
   virtual void delete_children (bool clear = false)
   {
     children.delete_children (clear);
@@ -2663,7 +2665,7 @@
     bool_property selectionhighlight , "on"
     string_property tag s , ""
     string_property type frs , ty
-    handle_property uicontextmenu , graphics_handle ()
+    handle_property uicontextmenu u , graphics_handle ()
     any_property userdata , Matrix ()
     bool_property visible , "on"
     // additional (Octave-specific) properties
@@ -5355,6 +5357,15 @@
   class OCTINTERP_API properties : public base_properties
   {
   public:
+  
+    void add_dependent_obj (graphics_handle gh) 
+    { dependent_obj_list.push_back (gh); }
+
+    // FIXME: the list may contain duplicates. 
+    //        Should we return only unique elements? 
+    const std::list<graphics_handle> get_dependent_obj_list (void) 
+    { return dependent_obj_list; }
+
     // See the genprops.awk script for an explanation of the
     // properties declarations.
     // Programming note: Keep property list sorted if new ones are added.
@@ -5372,6 +5383,10 @@
       position.add_constraint (dim_vector (2, 1));
       visible.set (octave_value (true));
     }
+
+  private:
+    // List of objects that might depend on this uicontextmenu object
+    std::list<graphics_handle> dependent_obj_list;
   };
 
 private:
@@ -5382,7 +5397,7 @@
     : base_graphics_object (), xproperties (mh, p)
   { }
 
-  ~uicontextmenu (void) { }
+  ~uicontextmenu (void);
 
   base_properties& get_properties (void) { return xproperties; }
 
