title: How to make the edges of needed form in jgraphx's graph?
body: <p>My graph contains rectangular vertices with single outgoing edge and the vertices of rhombus shape with two outgoing edges. </p>
  
  <p>I'm using <code>mxCompactTreeLayout</code> and mostly everything is ok except that edges of the vertices  of the second type look wrong for me. </p>
  
  <p>I want them to look like in the picture<img src="https://i.stack.imgur.com/3m9fK.png" alt="rhombus shaped vertex with two edges"></p>
  
  <p>Instead, edges connected to the bottom segments of the rhombus.</p>
  
  <p>What should I do to get edges look as desired. </p>
  
  <p>EDIT: Added source code.</p>
  
  <p>PtNodeVertex.java    </p>
  
  <pre><code>package org.jsc.core.visualization.jgraphx;
  
  import com.mxgraph.model.mxCell;
  import com.mxgraph.model.mxGeometry;
  import com.mxgraph.util.mxPoint;
  import com.mxgraph.util.mxRectangle;
  import com.mxgraph.util.mxUtils;
  import org.jsc.core.ast.IResult;
  import org.jsc.core.ptree.INodeCompleter;
  import org.jsc.core.ptree.PtNode;
  import org.jsc.core.term.ITerm;
  import org.jsc.core.term.MethodInvocationTerm;
  import org.jsc.core.term.expressions.ConditionalExpression;
  import org.jsc.core.term.expressions.InstanceCreationExpression;
  import org.jsc.core.term.expressions.VariableDeclarationTerm;
  import org.jsc.core.term.statement.BlockTerm;
  import org.jsc.core.term.statement.IfElse;
  import org.jsc.core.term.statement.SwitchStatement;
  import org.jsc.core.visualization.jgraphx.Edge.EdgeType;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import static java.lang.Math.max;
  import static java.lang.String.format;
  
  class PtNodeVertex extends mxCell
  {
      private static Map&lt;PtNode, PtNodeVertex&gt; completingNodesToViews = new HashMap&lt;PtNode, PtNodeVertex&gt;();
  
      private final PtNode node;
  
      protected mxCell[] labels;
  
      private List&lt;PtNodeVertex&gt; successors = new ArrayList&lt;PtNodeVertex&gt;( 1 );
  
      private PtNodeVertex predecessor;
  
      protected Edge[] edgeArray;
  
      private int index;
  
      PtNodeVertex( Object parent, PtNode value, String style )
      {
          super( parent, null, style );
  
          node = value;
  
          setVertex( true );
          setVisible( true );
          setGeometry( new mxGeometry() );
          setStyle( "defaultVertex;fillColor=none;strokeColor=black;strokeWidth=2.5" );
  
          labels = new mxCell[ getLabelsCount() ];
  
          createLabels();
          calcBounds();
          createEdges();
      }
  
      protected Edge[] createEdges()
      {
          int n = getMaxSuccessorsCount();
          if ( n == 0 )
          {
              return new Edge[ 0 ];
          }
          edgeArray = new Edge[ n ];
          Edge edge = new Edge( null, this );
          edgeArray[ 0 ] = edge;
  
          return edgeArray;
      }
  
      int getLabelsCount()
      {
          return 4;
      }
  
      int getMaxSuccessorsCount()
      {
          return 1;
      }
  
      final PtNode getNode()
      {
          return node;
      }
  
      protected void createLabels()
      {
          ITerm t = node.getTerm();
          IResult tv = node.getTermValue();
  
          labels[ 0 ] = createTextLabel( format( "Term [%s]:", t.getClass().getSimpleName() ) );
          labels[ 1 ] = createTextLabel( node.getTerm().toString(), true );
          labels[ 2 ] = createTextLabel( format( "Term value: %s", tv == null ? "n/a" : tv ) );
          labels[ 3 ] = createTextLabel( format( "State: %s", node.getState() ) );
      }
  
      protected void calcBounds()
      {
          mxGeometry b0 = labels[ 0 ].getGeometry();
          mxGeometry b1 = labels[ 1 ].getGeometry();
          mxGeometry b2 = labels[ 2 ].getGeometry();
          mxGeometry b3 = labels[ 3 ].getGeometry();
  
          double w = Math.max( b0.getWidth(), Math.max( b1.getWidth(), Math.max( b2.getWidth(), b3.getWidth() ) ) );
          double h = b0.getHeight() + b1.getHeight() + b2.getHeight() + b3.getHeight();
  
  
          mxGeometry b = getGeometry();
          double x = b.getX() + 5;
          double y = b.getY() + 5;
  
          double x2 = x;//+ 5 + w01 + 5;
          double y2 = y;
  
          double x3 = x2;
          double y3 = y2 + b2.getHeight();
  
          double x0 = x;
          double y0 = y3 + b3.getHeight();
  
          double x1 = x0;
          double y1 = y0 + b0.getHeight();
  
          b.setWidth( w + 10 );
          b.setHeight( h + 10 );
  
          b0.setX( x0 );
          b0.setY( y0 );
  
          b1.setX( x1 );
          b1.setY( y1 );
  
          b2.setX( x2 );
          b2.setY( y2 );
  
          b3.setX( x3 );
          b3.setY( y3 );
      }
  
      private static String prepareText( String s )
      {
          s = adjustNL( s );
          //    s = StringEscapeUtils.unescapeHtml4( s );
  
          return s;
      }
  
      private static String adjustNL( String s )
      {
          s = s.replaceAll( "\r\n", "\n" );
          s = s.replaceAll( "\r", "\n" );
  
          return s;
      }
  
      protected mxCell createTextLabel( String text )
      {
          return createTextLabel( text, false );
      }
  
      protected mxCell createTextLabel( String text, boolean framed )
      {
          mxCell label = new mxCell();
        //  System.out.print( text );
          text = prepareText( text );
          //        text = mxUtils.createHtmlDocument( new HashMap&lt;String, Object&gt;(), text, 1, 0,
          //                "&lt;style type=\"text/css\"&gt;.selectRef { " +
          //                        "font-size:9px;font-weight:normal; }&lt;/style&gt;" );
          label.setValue( text );
          mxRectangle b = mxUtils.getLabelSize( text, new HashMap&lt;String, Object&gt;(), false, 1.0 );
          mxGeometry geometry = new mxGeometry( b.getX(), b.getY(), b.getWidth(), b.getHeight() );
  
          label.setVertex( true );
          label.setGeometry( geometry );
          label.setVisible( true );
          label.setParent( this );
          this.insert( label );
          label.setConnectable( false );
          label.setStyle( format( "defaultVertex;fillColor=none%s", ( framed ? ";strokeColor=blue" : ";strokeColor=none" ) ) );
  
          return label;
      }
  
      public static mxCell create( Object parent, PtNode node, String style )
      {
          PtNodeVertex vertex;
  
          if ( isCompletingNode( node ) )
          {
              vertex = new PtNodeVertex( parent, node, style );
  
              completingNodesToViews.put( node, vertex );
          }
          else if ( node instanceof INodeCompleter )
          {
              vertex = new NodeCompleterVertex( parent, node, style );
              completingNodesToViews.put( node, vertex );
          }
          else if ( node.getTerm() instanceof IfElse )
          {
              vertex = new IfElseNodeVertex( parent, node, style );
          }
          else if ( node.getTerm() instanceof ConditionalExpression )
          {
              vertex = new ConditionalNodeVertex( parent, node, style );
          }
          else if ( node.getTerm() instanceof SwitchStatement )
          {
              vertex = new SwitchNodeVertex( parent, node, style );
          }
          else
          {
              vertex = new PtNodeVertex( parent, node, style );
          }
  
          return vertex;
      }
  
      private static boolean isCompletingNode( PtNode node )
      {
          return node.getTerm() instanceof BlockTerm ||
                  node.getTerm() instanceof VariableDeclarationTerm ||
                  node.getTerm() instanceof InstanceCreationExpression ||
                  node.getTerm() instanceof MethodInvocationTerm;
      }
  
      Object getLabel( int i )
      {
          return labels[ i ];
      }
  
      final int getSuccessorCount()
      {
          return successors.size();
      }
  
      void addSuccessor( PtNodeVertex successor )
      {
          successors.add( successor );
          successor.predecessor = this;
      }
  
      final PtNodeVertex getSuccessor( int i )
      {
          return successors.get( i );
      }
  
      final Edge getEdge( int i )
      {
          return edgeArray[ i ];
      }
  
      protected EdgeType getDefaultEdgeType()
      {
          return EdgeType.TYPE_1;
      }
  
      public void setIndex( int index )
      {
          this.index = index;
      }
  
      public int getIndex()
      {
          return index;
      }
  }
  `
  </code></pre>
  
  <p>IfElseNodeVertex.java</p>
  
  <pre><code>package org.jsc.core.visualization.jgraphx;
  
  import com.mxgraph.model.mxGeometry;
  import com.mxgraph.util.mxPoint;
  import org.jsc.core.ptree.PtNode;
  import org.jsc.core.term.statement.IfElse;
  import org.jsc.core.visualization.jgraphx.Edge.EdgeType;
  
  import static java.lang.Math.max;
  import static java.lang.String.format;
  import static org.jsc.core.visualization.jgraphx.Direction.LEFT;
  import static org.jsc.core.visualization.jgraphx.Direction.RIGHT;
  
  class IfElseNodeVertex extends PtNodeVertex
  {
      private Edge thenEdge;
      private Edge elseEdge;
  
  
      IfElseNodeVertex( Object parent, PtNode value, String style )
      {
          super( parent, value, style );
  
          if ( value.getTerm().getClass() != IfElse.class )
          {
              throw new Error( "IfElse term expected" );
          }
          if ( value.getOuts().size() != 2 )
          {
              throw new Error( "IfElse must have 2 successors\n" + value.getTerm() );  //or mat have 1 (without else
          }
          setStyle( "vRhombus;`fillColor=none;strokeColor=green" ); 
      }
  
      @Override
      protected void createLabels()
      {
          IfElse ifElse = ( IfElse ) getNode().getTerm();
          String termString = format( "if( %s )", ifElse.getCondition() );
          labels[ 0 ] = createTextLabel( termString );
          labels[ 0 ].setStyle( "\"vRhombus;shape=rhombus;fillColor=none;strokeColor=none" );
          labels[ 0 ].setGeometry( new mxGeometry( 0, 0, 300, 150 ) );
      }
  
      @Override
      protected void calcBounds()
      {
          mxGeometry b0 = labels[ 0 ].getGeometry();
  
          double w = 50 + b0.getWidth() + 50;
          double h = max( b0.getHeight(), w * 0.618 );
  
          mxGeometry b = getGeometry();
          double x = b.getX();
          double y = b.getY();
  
          double x0 = b0.getCenterX() - b0.getWidth() / 2;
          double y0 = b0.getCenterY();
  
          b.setWidth( 300 );
          b.setHeight( 150 );
      }
  
      @Override
      public int getLabelsCount()
      {
          return 1;
      }
  
      protected Edge[] createEdges()
      {
          int n = getMaxSuccessorsCount();
          if ( n == 0 )
          {
              return new Edge[ 0 ];
          }
          edgeArray = new Edge[ n ];
  
          thenEdge = new IfElseEdge( null, this, "then", EdgeType.TYPE_2, LEFT );
          elseEdge = new IfElseEdge( null, this, "else", EdgeType.TYPE_2, RIGHT );
  
          edgeArray[ 0 ] = thenEdge;
          edgeArray[ 1 ] = elseEdge;
  
          return edgeArray;
      }
  
      @Override
      public int getMaxSuccessorsCount()
      {
          return 2;
      }
  
      protected EdgeType getDefaultEdgeType()
      {
          return EdgeType.TYPE_2;
      }
  }
  </code></pre>
  
  <p>PtGraph.java</p>
  
  <pre><code>package org.jsc.core.visualization.jgraphx;
  
  import com.mxgraph.canvas.mxICanvas;
  import com.mxgraph.layout.mxCompactTreeLayout;
  import com.mxgraph.model.mxCell;
  import com.mxgraph.model.mxGeometry;
  import com.mxgraph.view.mxCellState;
  import com.mxgraph.view.mxGraph;
  import org.jsc.core.ptree.PtEdge;
  import org.jsc.core.ptree.PtNode;
  
  public class PtGraph extends mxGraph
  {
      private mxCompactTreeLayout layout;
  
      @Override
      public Object insertVertex( Object parent,
                                  String id,
                                  Object value,
                                  double x,
                                  double y,
                                  double width,
                                  double height,
                                  String style,
                                  boolean relative )
      {
          Object v = super.insertVertex( parent, id, value, x, y, width, height, style, relative );
  
          if ( v instanceof PtNodeVertex )
          {
              insertLabels( ( PtNodeVertex ) v );
          }
  
          return v;
      }
  
      protected void insertLabels( PtNodeVertex v )
      {
          for ( int i = 0; i &lt; v.getLabelsCount(); i++ )
          {
              addCell( v.getLabel( i ), v );
          }
      }
  
      @Override
      public Object createVertex( Object parent,
                                  String id,
                                  Object value,
                                  double x,
                                  double y,
                                  double width,
                                  double height,
                                  String style,
                                  boolean relative
      )
      {
          if ( !( value instanceof PtNode ) )
          {
              return super.createVertex( parent, id, value, x, y, width, height, style, relative );
          }
  
          mxCell vertex;
          PtNode node = ( PtNode ) value;
          if ( node == ProcessTreeSVGView.dummyNode )
          {
              vertex = new HaltVertex( parent );
          }
          else
          {
              vertex = PtNodeVertex.create( parent, node, null );
          }
          vertex.setId( id );
          vertex.setVertex( true );
          vertex.setConnectable( true );
          mxGeometry geometry = new mxGeometry( x, y, width, height );
          vertex.setGeometry( geometry );
  
          return vertex;
      }
      @Override
      public Object createEdge( Object parent,
                                String id,
                                Object value,
                                Object source,
                                Object target,
                                String style )
      {
          if ( !( value instanceof PtEdge ) )
          {
              return super.createEdge( parent, id, value, source, target, style );
          }
          PtEdge ptEdge = ( PtEdge ) value;
          Edge edge = ( Edge ) Edge.create( parent, ( PtNodeVertex ) source, (PtNodeVertex)target, ptEdge.getContext(), null, layout );
          edge.setId( id );
  
          edge.setConnectable( false );
  
          return edge;
      }
  
      @Override
      public void drawState( mxICanvas canvas, mxCellState state, boolean drawLabel )
      {
          Object cell = state.getCell();
          drawLabel = !( cell instanceof PtNodeVertex ) &amp;&amp; drawLabel;
  
          super.drawState( canvas, state, drawLabel );
      }
  
      public void setLayout( mxCompactTreeLayout layout )
      {
          this.layout = layout;
      }
  }
  </code></pre>
  
  <p>Edge.java</p>
  
  <pre><code>package org.jsc.core.visualization.jgraphx;
  
  import com.mxgraph.layout.mxCompactTreeLayout;
  import com.mxgraph.model.mxCell;
  import com.mxgraph.model.mxGeometry;
  import org.jsc.core.DriveContext;
  
  class Edge extends mxCell
  {
      enum EdgeType
      {
          TYPE_1,
          TYPE_2
      }
  
      static mxCell create( Object parent,
                            PtNodeVertex source,
                            PtNodeVertex target,
                            DriveContext context,
                            String style,
                            mxCompactTreeLayout layout )
      {
          int index = target.getIndex();
          Edge edge = source.getEdge( index );
          edge.setValue( context );
          edge.setEdge( true );
          edge.setLayoutParamsForEdge( layout );
  
          return edge;
      }
  
      protected void setLayoutParamsForEdge( mxCompactTreeLayout layout )
      {
      }
  
      Edge( Object parent, PtNodeVertex source )
      {
          mxGeometry geo = new mxGeometry();
          setEdge( true );
          setGeometry( geo );
      }
  }
  
  class IfElseEdge extends Edge
  {
      EdgeType type;
      Direction direction;
  
      IfElseEdge( Object parent, IfElseNodeVertex source, String text, EdgeType type, Direction direction )
      {
          super( parent, source );
  
          this.type = type;
          this.direction = direction;
  
          mxGeometry geo = new mxGeometry( 0, 0, 0, 0 );
          //geo.setRelative( true );
          setGeometry( geo );
  
          setStyle( "rhombusEdge" );
  
          mxCell sourceLabel = new mxCell( text, new mxGeometry( -1, 0, 0, 0 ),
                  direction == Direction.RIGHT ?
                          "resizable=0;align=left;verticalAlign=top;" :
                          "resizable=0;align=right;verticalAlign=top;"
          );
          sourceLabel.getGeometry().setRelative( true );
          sourceLabel.setConnectable( false );
          sourceLabel.setVertex( true );
  
          insert( sourceLabel );
  
      }
  
      @Override
      protected void setLayoutParamsForEdge( mxCompactTreeLayout layout )
      {
          layout.setOrthogonalEdge( this, true );
          layout.setEdgeStyleEnabled( this, true );
      }
  }
  </code></pre>
  
  <p>ProcessTreeSVGView.java</p>
  
  <pre><code>package org.jsc.core.visualization.jgraphx;
  
  import com.mxgraph.layout.mxCompactTreeLayout;
  import com.mxgraph.model.mxCell;
  import com.mxgraph.swing.mxGraphComponent;
  import com.mxgraph.util.mxConstants;
  import com.mxgraph.view.mxGraph;
  import com.mxgraph.view.mxPerimeter;
  import com.mxgraph.view.mxStylesheet;
  import org.apache.batik.dom.svg.SVGDOMImplementation;
  import org.apache.batik.svggen.SVGGraphics2D;
  import org.apache.batik.svggen.SVGGraphics2DIOException;
  import org.jsc.core.ptree.ProcessTree;
  import org.jsc.core.ptree.PtEdge;
  import org.jsc.core.ptree.PtNode;
  import org.w3c.dom.DOMImplementation;
  import org.w3c.dom.Element;
  import org.w3c.dom.svg.SVGDocument;
  
  import java.awt.*;
  import java.io.*;
  import java.util.Hashtable;
  import java.util.Map;
  
  public class ProcessTreeSVGView
  {
      private static final String SVG_FILE_NAME = "C:\\users\\anthony\\g.svg";
  
      static SVGGraphics2D g;
  
      private final mxGraph graph;
      private final mxGraphComponent graphComponent;
      private String style;
  
      public final static PtNode dummyNode = new PtNode();
      public final static PtEdge dummyEdge = new PtEdge();
  
      /**
       * Constructs a new frame that is initially invisible.
       * &lt;p&gt;
       * This constructor sets the component's locale property to the value
       * returned by &lt;code&gt;JComponent.getDefaultLocale&lt;/code&gt;.
       *
       * @exception java.awt.HeadlessException if GraphicsEnvironment.isHeadless()
       * returns true.
       * @see java.awt.GraphicsEnvironment#isHeadless
       * @see java.awt.Component#setSize
       * @see java.awt.Component#setVisible
       * @see javax.swing.JComponent#getDefaultLocale
       */
      public ProcessTreeSVGView( ProcessTree pTree )
              throws HeadlessException, SVGGraphics2DIOException, FileNotFoundException, UnsupportedEncodingException
      {
          System.out.printf( "\nSaving Process tree(s) in '%s' ... ", SVG_FILE_NAME );
          // Create an SVG document.
          DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
          String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
          SVGDocument doc = ( SVGDocument ) impl.createDocument( svgNS, "svg", null );
  
          // Create a converter for this document.
          g = new SVGGraphics2D( doc );
          graph = new PtGraph();
          graphComponent = new mxGraphComponent( graph );
  
          //First draw Graph to the SVGGraphics2D object using graph component objects draw method
          drawTree( pTree );
  
          // Do some drawing.
          graphComponent.getGraphControl().drawGraph( g, true );
  
          // Populate the document root with the generated SVG content.
          Element root = doc.getDocumentElement();
          g.getRoot( root );
  
          //Once every thing is drawn on graphics find root element and update this by adding additional values for the required fields.
          // Element root = g.getRoot();
          Dimension size = graphComponent.getGraphControl().getPreferredSize();
  
          root.setAttributeNS( null, "width", size.width + "" );
          root.setAttributeNS( null, "height", size.height + "" );
          root.setAttributeNS( null, "viewBox", "0 0 " + size.width + " " + size.height );
  
  
          OutputStream outStream = new FileOutputStream( SVG_FILE_NAME );
          Writer out = new OutputStreamWriter( outStream, "UTF-8" );
          g.stream( root, out );
  
          System.out.println( "done." );
  
          runSVGViewer( SVG_FILE_NAME );
      }
  
      private void runSVGViewer( String svgFileName )
      {
          System.out.print( "\nLoading SVG viewer ... " );
          ProcessBuilder builder = new ProcessBuilder( "C:\\Program Files (x86)\\Free Picture Solutions\\Free Svg Viewer\\SvgViewer.exe ", svgFileName );
          try
          {
              builder.start();
          }
          catch ( IOException e )
          {
              e.printStackTrace();
              throw new Error();
          }
          System.out.println( "done." );
      }
  
      //==================================================================================================================
  
      private void drawTree( ProcessTree pTree )
      {
          Object parent = graph.getDefaultParent();
  
          registerRhombusVertexStyle( graph );
  
          mxCompactTreeLayout layout = setupLayout( graph );
  
          graph.getModel().beginUpdate();
          mxCell v;
          try
          {
              v = build( pTree.getRoot(), ( mxCell ) parent, 0 );
          }
          finally
          {
              graph.getModel().endUpdate();
          }
  
          layout.execute( parent, v );
  
      }
  
      private mxCompactTreeLayout setupLayout( mxGraph graph )
      {
          mxCompactTreeLayout layout = new mxCompactTreeLayout( graph, false );
  
          layout.setEdgeRouting( true );
          layout.setHorizontal( false );
          layout.setLevelDistance( 100 );
          layout.setNodeDistance( 50 );
  
          layout.setUseBoundingBox( true );
  
          ( ( PtGraph ) graph ).setLayout( layout );
  
          return layout;
      }
  
      private PtNodeVertex build( PtNode node, mxCell parent, int index )
      {
          PtNodeVertex source = insertVertex( node, parent, index );
          if ( node.getChildrenCount() == 0 )
          {
              HaltVertex target = ( HaltVertex ) insertHaltVertex( parent );
  
              source.addSuccessor( target );
              insertEdge( parent, dummyEdge, source, target );
  
              return source;
          }
  
          for ( int i = 0; i &lt; node.getChildrenCount(); i++ )
          {
              PtNode node1 = node.getChild( i );
  
              PtNodeVertex target = build( node1, parent, i );
  
              source.addSuccessor( target );
              insertEdge( parent, node1.getIn(), source, target );
          }
  
          return source;
      }
  
      PtNodeVertex insertVertex( PtNode node, mxCell parent, int index )
      {
          PtNodeVertex v = ( PtNodeVertex ) graph.insertVertex( parent, null, node, 0, 0, 0, 0, style );
          v.setIndex( index );
  
          return v;
      }
  
      private mxCell insertHaltVertex( mxCell parent )
      {
          mxCell v = ( mxCell ) graph.insertVertex( parent, null, dummyNode, 0, 0, 0, 0, style );
  
          return v;
      }
  
      private void insertEdge( Object parent, PtEdge ptEdge, mxCell source, mxCell target )
      {
          if ( !( source instanceof HaltVertex ) )
          {
              graph.insertEdge( parent, null, ptEdge, source, target );
          }
      }
  
      private static void registerRhombusVertexStyle( mxGraph graph )
      {
          mxStylesheet ss = graph.getStylesheet();
  
          Map&lt;String, Object&gt; style = new Hashtable&lt;String, Object&gt;();
  
          style.put( mxConstants.STYLE_SHAPE, mxConstants.SHAPE_RHOMBUS );
          style.put( mxConstants.STYLE_PERIMETER, mxPerimeter.RhombusPerimeter );
          style.put( mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE );
          style.put( mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER );
          style.put( mxConstants.STYLE_FILLCOLOR, "#C3D9FF" );
          style.put( mxConstants.STYLE_STROKECOLOR, "#6482B9" );
          style.put( mxConstants.STYLE_FONTCOLOR, "#774400" );
  
          ss.putCellStyle( "vRhombus", style );
  
          style = ss.getDefaultEdgeStyle();
          style.put( mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ELBOW );
          style.put( mxConstants.STYLE_ROUTING_CENTER_Y, 0.0 );
  
          ss.putCellStyle( "rhombusEdge", style );
  
  ////////////////////////////////////////////////////////////////////////////////////
          Map&lt;String, Map&lt;String, Object&gt;&gt; styles = ss.getStyles();
  
          for ( String key : styles.keySet() )
          {
              Map&lt;String, Object&gt; _style = styles.get( key );
              System.out.printf( "\n%s =\n", key );
              System.out.println( "---------------------" );
  
              for ( String key1 : _style.keySet() )
              {
                  System.out.printf( "\n%s = %s", key1, _style.get( key1 ) );
              }
              System.out.println();
          }
  
      }
  }
  </code></pre>