@Override
 public int compare(GraphObject t0, GraphObject t1) {
   long x0 = t1.getReturnTime(t0);
   long x1 = t0.getReturnTime(t1);
   if (x0 == x1) { // either same or == 0
     long d = t0.getStartTime() - t1.getStartTime();
     if (d < 0) return -1;
     else if (d > 0) return 1;
     else if (t0.getName() == null) return -1;
     else if (t1.getName() == null) return 1;
     else return t0.getName().compareTo(t1.getName());
   } else if (x0 == 0) return -1;
   else if (x1 == 0) return 1;
   else if (x0 < x1) return 1;
   else return -1;
 }
 @Override
 public String getToolTipText(MouseEvent e) {
   BddtHistoryItem itm = getItemAtPoint(e.getX(), e.getY());
   if (itm != null) {
     StringBuffer buf = new StringBuffer();
     BumpThreadStack stk = itm.getStack();
     BumpStackFrame frm = stk.getFrame(0);
     if (frm == null) return null;
     buf.append(frm.getMethod() + " at " + frm.getLineNumber());
     return buf.toString();
   }
   GraphObject go = getObjectAtPoint(e.getX(), e.getY());
   if (go != null) {
     return go.getName();
   }
   return null;
 }
  private void drawObject(Graphics2D g, int idx, GraphObject go) {
    double x0 = left_right_margin + (object_width + object_hspacing) * idx;
    Rectangle2D r = new Rectangle2D.Double(x0, top_bottom_margin, object_width, object_height);
    graph_locations.put(go, x0 + object_width / 2);

    g.setColor(Color.WHITE);
    g.fill(r);
    g.setColor(Color.BLACK);
    g.draw(r);
    g.setColor(Color.RED);
    SwingText.drawText(go.getName(), g, r);

    double x1 = x0 + object_width / 2;
    double y1 = top_bottom_margin + object_height;
    double y2 = time_end;
    Line2D tl = new Line2D.Double(x1, y1, x1, y2);
    g.setColor(Color.BLACK);
    g.draw(tl);

    for (GraphBlock gb : go.getBlocks()) {
      drawBlock(g, x1, gb);
    }
  }