public void validateBounds(Graphics g) {
   if (!needCheckBounds && !needCheckTextBounds) return;
   super.validateBounds(g);
   // reset position to point the arrow point
   int x = bounds.x + bounds.width - RenderableGene.GENE_SYMBOL_PAD;
   int y = textBounds.y - RenderableGene.GENE_SYMBOL_WIDTH / 2;
   setArrowPoint(x, y);
 }
 private void drawComponents(
     Graphics g, List<Renderable> comps, Rectangle clip, boolean drawEdgeFirst) {
   List<HyperEdge> edges = new ArrayList<HyperEdge>();
   for (Renderable obj : comps) {
     if (obj instanceof HyperEdge) edges.add((HyperEdge) obj);
   }
   if (drawEdgeFirst) {
     // Draw HyperEdges
     for (HyperEdge reaction : edges) {
       // Have to validate connect nodes first in case empty bounds
       List<Node> nodes = reaction.getConnectedNodes();
       for (Node node : nodes) node.validateBounds(g);
       reaction.validateConnectInfo();
       if (clip.intersects(reaction.getBounds())) reaction.render(g);
     }
   }
   // Draw complexes now
   drawComplexes(comps, clip, g);
   for (Renderable obj : comps) {
     if (obj instanceof RenderableCompartment
         || obj instanceof RenderableComplex
         || obj instanceof RenderablePathway) continue; // Escape it. It should be drawn earlier.
     if (obj instanceof Node) {
       Node node = (Node) obj;
       if (getHidePrivateNote() && (node instanceof Note) && ((Note) node).isPrivate()) continue;
       node.validateBounds(g);
       if (clip.intersects(node.getBounds())) node.render(g);
     }
   }
   if (!drawEdgeFirst) {
     // Draw HyperEdges
     for (HyperEdge reaction : edges) {
       reaction.validateConnectInfo();
       if (clip.intersects(reaction.getBounds())) reaction.render(g);
     }
   }
 }