/*
 * Licensed Materials - Property of Rogue Wave Software, Inc. 
 * © Copyright Rogue Wave Software, Inc. 2014, 2015 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */

import ilog.views.*;
import ilog.views.swing.*;
import ilog.views.util.swing.IlvDecimalNumberField;
import ilog.views.util.swing.IlvSwingUtil;
import ilog.views.util.swing.IlvJComboBox;
import ilog.views.graphic.*;
import ilog.views.graphic.composite.IlvCompositeGraphic;
import ilog.views.graphic.composite.IlvEventMap;
import ilog.views.graphic.composite.layout.IlvAttachmentConstraint;
import ilog.views.graphic.composite.layout.IlvAttachmentLayout;
import ilog.views.graphic.composite.layout.IlvAttachmentLocation;
import ilog.views.graphic.composite.layout.IlvStackerLayout;
import ilog.views.graphic.composite.objectinteractor.IlvCompositeContext;
import ilog.views.graphic.composite.objectinteractor.IlvCompositeInteractor;
import ilog.views.interactor.*;
import ilog.views.accelerator.*;
import ilog.views.event.*;
import ilog.views.util.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;

/**
 * This sample shows how to use the utility method 
 * <code>ilog.views.IlvGrapher#setVisibleBranch(IlvGraphic, int, boolean, boolean)</code>.
 */
public class ShowHideBranch 
  extends JApplet
{
  static {
    // This applet is designed to run only with default resource bundle
    // and various selected other resource bundles.
    // Setting the available resource suffixes avoids that the applet
    // tries to load resource bundles for other locales over the net,
    // even if the current locale of the browser is different.
    if (IlvResourceUtil.isInApplet())
      IlvResourceUtil.setAvailableResourceSuffixes("", "_ja");
  }

  {
    // This sample uses JViews Diagrammer features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Rogue Wave JViews Diagrammer Deployment license.
//    IlvProductUtil.DeploymentLicenseRequired(
//        IlvProductUtil.JViews_Diagrammer_Deployment);
  }

  IlvGrapher grapher;
  IlvManagerView mgrview;
  
  /** The panel containing buttons. */
  JPanel options;

  /** Array of buttons. */
  InteractorButton[] interactorButtons;
  
  private float minpos = 0;
  
  private int startLevel = 0;
  private int endLevel = -1;
  boolean intergraphLinks = false;
  boolean treeExtIntergraphLinks = false;
  
  /** The tree is created with this number of children for each node. */
  private static final int NUMBER_OF_CHILDREN = 2;

  /** How large the nodes should be. */
  private static final float NODE_WIDTH = 45;
  private static final float NODE_HEIGHT = 35;
  
  /** For laying out the nodes **/
  private static final int MIN_XSPACE = 60;
  private static final int MIN_YSPACE = 20;

  /** How thick the links should be. */
  private static final float LINK_WIDTH = 2;
  
  /** 
   * Initializes the applet.
   */
  public void init()
  {
    super.init();
    
    getContentPane().setLayout(new BorderLayout(0,0));

    // Creates the grapher.
    grapher = new IlvGrapher();

    // Creates the view of the grapher.
    mgrview = new IlvManagerView(grapher, null);
    mgrview.setKeepingAspectRatio(true);
    mgrview.setAntialiasing(true);
    mgrview.addInteractorListener(new InteractorListener() {
      public  void interactorChanged(InteractorChangedEvent evt)
      {
        IlvManagerViewInteractor newI = evt.getNewValue();
        for (int i = 0; i < interactorButtons.length; i++) {
          boolean select = interactorButtons[i].getInteractor() == newI;
          if (select != interactorButtons[i].isSelected()) {
            interactorButtons[i].removeItemListener(interactorButtons[i]);
            interactorButtons[i].setSelected(select);
            interactorButtons[i].addItemListener(interactorButtons[i]);
          }
        }
      }
    });
    
    // Setting parameters for selection handles.
    IlvHandlesSelection.defaultHandleColor = Color.black;
    IlvHandlesSelection.defaultHandleBackgroundColor = Color.white;
    IlvHandlesSelection.defaultHandleShape = IlvHandlesSelection.SQUARE_SHAPE;

    // Adds the graphic objects to the grapher.
    minpos = 0;
    addSubtree(0, 4, grapher);
    
    // Adds some accelerators.
    grapher.addAccelerator(new IlvIdentityAccelerator(KeyEvent.KEY_PRESSED,
                    KeyEvent.VK_I, 0));
    grapher.addAccelerator(new IlvZoomOutAccelerator(KeyEvent.KEY_PRESSED,
                    KeyEvent.VK_U, KeyEvent.CTRL_MASK));
    grapher.addAccelerator(new IlvZoomInAccelerator(KeyEvent.KEY_PRESSED,
                                                    KeyEvent.VK_Z, KeyEvent.CTRL_MASK));
    grapher.addAccelerator(new IlvFitToSizeAccelerator(KeyEvent.KEY_PRESSED, 
                                                       KeyEvent.VK_F, 0));
    grapher.addAccelerator(new IlvRotateAccelerator(KeyEvent.KEY_PRESSED, 
                                                    KeyEvent.VK_R, 0));
    grapher.addAccelerator(new IlvSelectAllAccelerator(KeyEvent.KEY_PRESSED,
                    KeyEvent.VK_A, KeyEvent.CTRL_MASK));
    grapher.addAccelerator(new IlvScrollUpAccelerator(KeyEvent.KEY_PRESSED,
                                                      KeyEvent.VK_UP, 0));
    grapher.addAccelerator(new IlvScrollDownAccelerator(KeyEvent.KEY_PRESSED,
                                                        KeyEvent.VK_DOWN, 0));
    grapher.addAccelerator(new IlvScrollRightAccelerator(KeyEvent.KEY_PRESSED,
                                                         KeyEvent.VK_RIGHT, 0));
    grapher.addAccelerator(new IlvScrollLeftAccelerator(KeyEvent.KEY_PRESSED,
                                                        KeyEvent.VK_LEFT, 0));
    

    IlvJScrollManagerView scview = new IlvJScrollManagerView(mgrview);
    
    mgrview.setWheelZoomingEnabled(true);
    scview.setWheelScrollingEnabled(true);
    
    getContentPane().add(scview, BorderLayout.CENTER);

    // Allows the user to delete nodes by pressing the "del" key.
    grapher.addAccelerator(new IlvDeleteSelectionAccelerator(
                                  KeyEvent.KEY_PRESSED, KeyEvent.VK_DELETE, 0));

    // Creates the options panel.
    JPanel optionsPanel;
    getContentPane().add(optionsPanel = new JPanel(), BorderLayout.WEST);
    optionsPanel.setLayout(new BorderLayout(0,0));
    options = new JPanel();
    optionsPanel.add(options, BorderLayout.NORTH);
    options.setLayout(new GridLayout(0,1,1,1));
    initOptionsPanel();
  }

  /**
   * Adds one interactor button.
   */
  void addButtonInteractor(int index, String text,
                           String tooltip,
                           IlvManagerViewInteractor inter)                           
  {
    interactorButtons[index] = new InteractorButton(text, inter, tooltip, this);
    
    options.add(interactorButtons[index]); 
    interactorButtons[index].setSize(20,20);
  }

  /**
   * Adds all the interactor buttons and options GUI.
   */
  void initOptionsPanel() 
  {

    boolean opaque = true; // set the options in opaque mode
    int n = 0;
    interactorButtons = new InteractorButton[1];
    IlvSelectInteractor selInter = new IlvSelectInteractor();
    selInter.setOpaqueDragSelection(opaque);
    selInter.setOpaqueMove(opaque);
    selInter.setOpaqueResize(opaque);
    selInter.setOpaquePolyPointsEdition(opaque);
    selInter.setObjectInteractorEnabled(true);
    
    IlvMakePolyLinkInteractor makePolyLink = 
      new IlvMakePolyLinkInteractor() {
        public IlvLinkImage createObject(IlvGraphic from, IlvGraphic to, 
                                         IlvPoint[] points, boolean oriented) {
          IlvLinkImage link = super.createObject(from, to, points, oriented);
          link.setLineWidth(LINK_WIDTH);
          link.setOriented(true);
          return link;
      }
    };
    makePolyLink.setOpaqueMode(opaque);
    makePolyLink.setPermanent(false);
    makePolyLink.setForeground(Color.blue);
    addButtonInteractor(n++, "Create Link", 
                        "Allows the creation of a polyline links", makePolyLink);

    // ==============
    // level
    
    final IlvDecimalNumberField startLevelField = 
      new IlvDecimalNumberField(0, 1000, false);
    startLevelField.setText("0");
    startLevelField.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        String text = startLevelField.getText();
        Integer levelInt = new Integer(text);
        startLevel = levelInt.intValue();
      }
    });
    options.add(new JLabel("Start Level:"));
    options.add(startLevelField);

    final IlvDecimalNumberField endLevelField = 
      new IlvDecimalNumberField(-1, 1000, false);
    endLevelField.setText("-1");
    endLevelField.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        String text = endLevelField.getText();
        Integer levelInt = new Integer(text);
        endLevel = levelInt.intValue();
      }
    });
    options.add(new JLabel("End Level:"));
    options.add(endLevelField);


    // ============
    // Intergraph links

    final JComboBox linksModeBox = new IlvJComboBox();
    linksModeBox.addItem("Normal links");
    linksModeBox.addItem("Explicit intergraph links");
    linksModeBox.addItem("Implicit intergraph links");
    linksModeBox.addItem("Implicit subgraphs");
    linksModeBox.setEnabled(false);
    linksModeBox.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
          JComboBox comboBox = (JComboBox)event.getSource();
          String sel = (String)comboBox.getSelectedItem();
          if (sel.equals("Normal links")) {
            intergraphLinks = false;
            treeExtIntergraphLinks = false;
          } else if (sel.equals("Explicit intergraph links")) {
            intergraphLinks = true;
            treeExtIntergraphLinks = false;
          } else if (sel.equals("Implicit intergraph links")) {
            intergraphLinks = true;
            treeExtIntergraphLinks = true;
          } else if (sel.equals("Implicit subgraphs")) {
            intergraphLinks = false;
            treeExtIntergraphLinks = true;
          }
        }
      });

    // ============
    // nested

    final JCheckBox nestedCheckBox = new JCheckBox("Nested Graph", false);
    nestedCheckBox.addItemListener(new ItemListener() {
      public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
          minpos = 0;
          grapher.deleteAll(false);
          addNestedSubtree(0, 2, grapher);
          grapher.reDraw();
          linksModeBox.setEnabled(true);
        } else {
          minpos = 0;
          grapher.deleteAll(false);
          addSubtree(0, 4, grapher);
          grapher.reDraw();
          intergraphLinks = false;
          treeExtIntergraphLinks = false;
          linksModeBox.setSelectedIndex(0);
          linksModeBox.setEnabled(false);
        }
      }
    });
    options.add(nestedCheckBox);
    options.add(linksModeBox);
  }

  /**
   * Adds an object to the grapher.
   * It also adds the connection pin to the node.
   */
  void addNode(IlvGraphic node) 
  {
    grapher.addNode(node, 1, false);
  }

  public void start() 
  {
    // Ensures that the root object is in the middle.
    mgrview.translate(10, -grapher.boundingBox().height/2 + 
                          getHeight()/2, true);
  }

  /**
   * Called when this applet is being reclaimed in order to destroy
   * any resources that it has allocated.
   */
  public void destroy()
  {
    super.destroy();

    // This method is intended to workaround memory management issues
    // in the Sun JRE. Please refer to the method documentation for more
    // details and a description of the known issues.
    IlvSwingUtil.cleanupApplet();
  }
  
  /**
   * Generates a subtree and layout it. If ilog.views.graphlayout package
   * is available, this can advantageously be replaced by using a 
   * <code>ilog.views.graphlayout.tree.IlvTreeLayout</code>.
   * @param actlevel the actual level
   * @param maxlevel the maximal level
   * @param grapher the grapher
   * @return The root of the subtree.
   */
  private IlvGraphic addSubtree(int actlevel, int maxlevel, IlvGrapher grapher)
  {
    Color color = new Color(Math.min(50 + actlevel * 40, 255),
                            Math.min(50 + actlevel * 40, 255),
                            Math.min(100 + actlevel * 40, 255));

    IlvGraphic node = createNode(color);
    addNode(node);

    IlvRect rect;
    IlvGraphic child;
    IlvLinkImage link;
    float minChildPos = Float.MAX_VALUE;
    float maxChildPos = - Float.MAX_VALUE;

    if (actlevel < maxlevel) {
      for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
        child = addSubtree(actlevel+1, maxlevel, grapher);
        rect = child.boundingBox();
        minpos = Math.max(minpos, rect.y + rect.height + MIN_YSPACE);
        minChildPos = Math.min(minChildPos, rect.y);
        maxChildPos = Math.max(maxChildPos, rect.y + rect.height);
        link = new IlvPolylineLinkImage(node, child, true, null);
        link.setForeground(color);
        link.setLineWidth(2);
        grapher.addLink(link, 0, false);
      }
    }

    if (minChildPos < maxChildPos)
      grapher.moveObject(node,
                         actlevel * (NODE_WIDTH + MIN_XSPACE),
                         0.5f * (maxChildPos + minChildPos - NODE_HEIGHT),
                         false);
    else
      grapher.moveObject(node,
                         actlevel * (NODE_WIDTH + MIN_XSPACE),
                         minpos,
                         false);

    return node;
  }

  private IlvGraphic addNestedSubtree(int actlevel, int maxlevel, IlvGrapher grapher)
  {
    Color color = new Color(Math.min(50 + actlevel * 40, 255),
                            Math.min(50 + actlevel * 40, 255),
                            Math.min(100 + actlevel * 40, 255));

    IlvLinkImage link;
    IlvGrapher subgraph = new IlvGrapher();
    IlvGraphic node1 = createNode(color);
    subgraph.addNode(node1, false);
    subgraph.moveObject(node1, 0, -0.5f * NODE_HEIGHT, false);

    IlvGraphic node2 = createNode(color);
    subgraph.addNode(node2, false);
    subgraph.moveObject(node2, NODE_WIDTH + MIN_XSPACE,
                               -0.5f * NODE_HEIGHT, false);
    link = new IlvPolylineLinkImage(node1, node2, true, null);
    link.setForeground(color);
    link.setLineWidth(2);
    subgraph.addLink(link, 0, false);

    IlvGraphic node3 = null;
    if (actlevel < maxlevel) {
      node3 = createNode(color);
      subgraph.addNode(node3, false);
      link = new IlvPolylineLinkImage(node1, node3, true, null);
      link.setForeground(color);
      link.setLineWidth(2);
      subgraph.addLink(link, 0, false);
    }

    // add an invisible dummy object so that the subgraph stays at its
    // position even when all real nodes get invisible
    IlvGraphic dummy = new IlvRectangle(
                         new IlvRect(0, -0.5f * NODE_HEIGHT,
                                     2 * NODE_WIDTH + MIN_XSPACE,
                                     NODE_HEIGHT));
    dummy.setForeground(new Color(0,0,0,0));
    dummy.setBackground(new Color(0,0,0,0));
    subgraph.addObject(dummy, 0, false);

    // increase the margins of the manager frame
    IlvDefaultManagerFrame frame = (IlvDefaultManagerFrame)subgraph.getFrame();
    frame.setLeftMargin(10);
    frame.setRightMargin(10);
    frame.setOpaque(true);
    frame.setBackground(Color.yellow);

    addNode(subgraph);

    IlvRect rect;
    IlvGraphic child;
    IlvGraphic childBag;
    float minChildPos = Float.MAX_VALUE;
    float maxChildPos = - Float.MAX_VALUE;
    float childHeight = 0;

    if (actlevel < maxlevel) {
      for (int i = 0; i < 4; i++) {
        child = addNestedSubtree(actlevel+1, maxlevel, grapher);
        childBag = (IlvGraphic)child.getGraphicBag();
        rect = childBag.boundingBox();
        childHeight = rect.height;
        minpos = Math.max(minpos, rect.y + rect.height + MIN_YSPACE);
        minChildPos = Math.min(minChildPos, rect.y);
        maxChildPos = Math.max(maxChildPos, rect.y + rect.height);
        switch (i) {
          case 0:
            link = new IlvPolylineLinkImage(node2, child, true, null);
            break;
          case 1:
            link = new IlvPolylineLinkImage(subgraph, child, true, null);
            break;
          case 2:
            link = new IlvPolylineLinkImage(subgraph, childBag, true, null);
            break;
          case 3:
            link = new IlvPolylineLinkImage(node3, childBag, true, null);
            break;
        }
        link.setForeground(color);
        link.setLineWidth(2);
        grapher.addLink(link, 2, false);
      }
    }

    if (minChildPos < maxChildPos) {
      float dist = (maxChildPos - minChildPos - childHeight) / 2;
      subgraph.moveObject(node2, NODE_WIDTH + MIN_XSPACE,
                                 -dist - 0.5f * NODE_HEIGHT, false);
      subgraph.moveObject(node3, NODE_WIDTH + MIN_XSPACE, 
                                 dist - 0.5f * NODE_HEIGHT, false);
      subgraph.reshapeObject(dummy, 
                             new IlvRect(0, -dist - 0.5f * NODE_HEIGHT,
                                         2 * NODE_WIDTH + MIN_XSPACE,
                                         2 * dist + NODE_HEIGHT),
                             false);
      float height = subgraph.boundingBox().height;
      grapher.moveObject(subgraph,
                         2 * actlevel * (NODE_WIDTH + MIN_XSPACE),
                         0.5f * (maxChildPos + minChildPos - height),
                         false);
    } else {
      grapher.moveObject(subgraph,
                         2 * actlevel * (NODE_WIDTH + MIN_XSPACE),
                         minpos,
                         false);
    }

    return node1;
  }
  
  private IlvGraphic createNode(Color color)
  {
    final IlvCompositeGraphic node = new IlvCompositeGraphic();
    // Sets the layout
    IlvAttachmentLayout layout = new IlvAttachmentLayout();
    node.setLayout(layout);

    // Creates a white rectangle
    RoundRectangle2D.Float shape = 
      new RoundRectangle2D.Float(0, 0, NODE_WIDTH, NODE_HEIGHT, 10, 10);
    IlvGeneralPath path = new IlvGeneralPath(shape);
    path.setFillOn(true);
    path.setStroke(new BasicStroke(2));
    path.setForeground(Color.black);
    path.setBackground(Color.white);
    node.setChildren(0, path);

    // Creates the container for stacking the icons horizontally to the right
    IlvCompositeGraphic iconsTop = new IlvCompositeGraphic();
    IlvStackerLayout stackerTop = 
      new IlvStackerLayout(SwingConstants.RIGHT, SwingConstants.CENTER, 2);
    iconsTop.setLayout(stackerTop);

    IlvCompositeGraphic iconsBottom = new IlvCompositeGraphic();
    IlvStackerLayout stackerBottom = 
      new IlvStackerLayout(SwingConstants.RIGHT, SwingConstants.CENTER, 2);
    iconsBottom.setLayout(stackerBottom);
    
    // Create the decoration buttons
    IlvGraphic showOrig = createShowHideButtonDeco(true, true);
    iconsTop.setChildren(2, showOrig);
    
    IlvGraphic hideOrig = createShowHideButtonDeco(true, false);
    iconsBottom.setChildren(2, hideOrig);
    
    IlvGraphic showDest = createShowHideButtonDeco(false, true);
    iconsTop.setChildren(1, showDest);
    
    IlvGraphic hideDest = createShowHideButtonDeco(false, false);
    iconsBottom.setChildren(1, hideDest);

    // Attach the TopCenter (hotspot) of the stacker to the
    // TopCenter (anchor) of the rectangle
    node.setChildren(1, iconsTop);
    node.setConstraints(1, new IlvAttachmentConstraint(
                             IlvAttachmentLocation.TopCenter, 
                             IlvAttachmentLocation.TopCenter, 0, +1));
    
    // Attach the BottomCenter (hotspot) of the stacker to the
    // BottomCenter (anchor) of the rectangle
    node.setChildren(2, iconsBottom);
    node.setConstraints(2, new IlvAttachmentConstraint(
                             IlvAttachmentLocation.BottomCenter, 
                             IlvAttachmentLocation.BottomCenter, 0, -1));

    Action[] actionsShowOrig = {
      new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
          grapher.setVisibleBranch(node, startLevel, endLevel, true, true,
                                   intergraphLinks, treeExtIntergraphLinks);
          grapher.reDraw();
        }
      },
    };
    Action[] actionsHideOrig = {
      new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
          grapher.setVisibleBranch(node, startLevel, endLevel, false, true,
                                   intergraphLinks, treeExtIntergraphLinks);
          grapher.reDraw();
        }
      },
    };
    Action[] actionsShowDest = {
      new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
          grapher.setVisibleBranch(node, startLevel, endLevel, true, false,
                                   intergraphLinks, treeExtIntergraphLinks);
          grapher.reDraw();
        }
      },
    };
    Action[] actionsHideDest = {
      new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
          grapher.setVisibleBranch(node, startLevel, endLevel, false, false,
                                   intergraphLinks, treeExtIntergraphLinks);
          grapher.reDraw();
        }
      },
    };
    
    String[] events = {
      "BUTTON1_CLICKED",
    };
    
    // Show Origin
    IlvEventMap eventMapShowOrig = new IlvEventMap();
    eventMapShowOrig.setActions(actionsShowOrig);
    eventMapShowOrig.setEvents(events);
    iconsTop.setEventMaps(2, eventMapShowOrig);
    
    // Hide Origin
    IlvEventMap eventMapHideOrig = new IlvEventMap();
    eventMapHideOrig.setActions(actionsHideOrig);
    eventMapHideOrig.setEvents(events);
    iconsBottom.setEventMaps(2, eventMapHideOrig);
    
    // Show Destination
    IlvEventMap eventMapShowDest = new IlvEventMap();
    eventMapShowDest.setActions(actionsShowDest);
    eventMapShowDest.setEvents(events);
    iconsTop.setEventMaps(1, eventMapShowDest);
    
    // Hide Destination
    IlvEventMap eventMapHideDest = new IlvEventMap();
    eventMapHideDest.setActions(actionsHideDest);
    eventMapHideDest.setEvents(events);
    iconsBottom.setEventMaps(1, eventMapHideDest);
    
    IlvCompositeInteractor compInteractor = 
      new IlvCompositeInteractor() {
        public IlvCompositeContext getCompositeContext(Object source) {
          return null;
        }
    };
    node.setObjectInteractor(compInteractor);
    
    return node;
  }
  
  /**
   * Creates the decoration of the composite object (the node of
   * the grapher) for the button which allows either to expand or to
   * collapse a branch in a given direction.
   */ 
  private IlvGraphic createShowHideButtonDeco(boolean origin, boolean show)
  {
    // "o" stands for "origin", "d" for destination
    // "+" stands for "expand", "-" for collapse
    String text = (origin ? "o" : "d") + (show ? "+" : "-");
    IlvText buttonDeco = new IlvText(new IlvPoint(), text);
    buttonDeco.setFillOn(true);
    Color fillColor = show ? Color.green : Color.red;
    fillColor = fillColor.brighter().brighter().brighter();
    buttonDeco.setFillPaint(fillColor);
    float width = buttonDeco.boundingBox().width;
    buttonDeco.setLeftMargin(Math.max(0, (20-width) / 2));
    buttonDeco.setRightMargin(Math.max(0, (20-width) / 2));
    return buttonDeco;
  }
  
  /**
   * A button class that automatically installs an interactor.
   */
  private class InteractorButton 
    extends JToggleButton 
    implements ItemListener
  {
    private IlvManagerViewInteractor interactor;
    private ShowHideBranch editor;
    
    public InteractorButton(String text, 
                            IlvManagerViewInteractor inter, 
                            String tooltip,
                            ShowHideBranch editor)
    {
      super(text);
      this.editor = editor;
      this.interactor = inter;
      setToolTipText(tooltip);
      addItemListener(this);
    }
    
    IlvManagerViewInteractor getInteractor()
    {
      return interactor;
    }
    
    public void itemStateChanged(ItemEvent event)
    {
      if (isSelected()) {
        // Removes the previous interactor and installs a new one.
        editor.mgrview.popInteractor();
        editor.mgrview.pushInteractor(interactor);
      } else  
        editor.mgrview.popInteractor();
    }
  }
  
  public static void main(String[] args) 
  {
    // Sun recommends that to put the entire GUI initialization into the
    // AWT thread
    SwingUtilities.invokeLater(
      new Runnable() {
        public void run() {
          ShowHideBranch applet = new ShowHideBranch();
          applet.init();

          JFrame frame = new JFrame("Show-Hide Grapher Branch");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setSize(700, 600);
          frame.getContentPane().add(applet);
          frame.setVisible(true);
        }
      });
  }
}