Google Tag Manager

2011/08/29

FileSystemTree with JCheckBox

Code

class CheckBoxNodeEditor extends TriStateCheckBox implements TreeCellEditor {
  private final FileSystemView fileSystemView;
  private final JPanel panel = new JPanel(new BorderLayout());
  private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
  private File file;

  public CheckBoxNodeEditor(FileSystemView fileSystemView) {
    super();
    this.fileSystemView = fileSystemView;
    this.addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        stopCellEditing();
      }
    });
    panel.setFocusable(false);
    panel.setRequestFocusEnabled(false);
    panel.setOpaque(false);
    panel.add(this, BorderLayout.WEST);
    this.setOpaque(false);
  }

  @Override public Component getTreeCellEditorComponent(
      JTree tree, Object value, boolean isSelected, boolean expanded,
      boolean leaf, int row) {
    JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
      tree, value, true, expanded, leaf, row, true);
    l.setFont(tree.getFont());
    setOpaque(false);
    if (value instanceof DefaultMutableTreeNode) {
      this.setEnabled(tree.isEnabled());
      this.setFont(tree.getFont());
      Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
      if (userObject instanceof CheckBoxNode) {
        CheckBoxNode node = (CheckBoxNode) userObject;
        if (node.status == Status.INDETERMINATE) {
          setIcon(new IndeterminateIcon());
        } else {
          setIcon(null);
        }
        file = node.file;
        l.setIcon(fileSystemView.getSystemIcon(file));
        l.setText(fileSystemView.getSystemDisplayName(file));
        setSelected(node.status == Status.SELECTED);
      }
      // panel.add(this, BorderLayout.WEST);
      panel.add(l);
      return panel;
    }
    return l;
  }

  @Override public Object getCellEditorValue() {
    return new CheckBoxNode(file, isSelected() ? Status.SELECTED : Status.DESELECTED);
  }

  @Override public boolean isCellEditable(EventObject e) {
    if (e instanceof MouseEvent && e.getSource() instanceof JTree) {
      MouseEvent me = (MouseEvent) e;
      JTree tree = (JTree) e.getSource();
      TreePath path = tree.getPathForLocation(me.getX(), me.getY());
      Rectangle r = tree.getPathBounds(path);
      if (r == null) {
        return false;
      }
      Dimension d = getPreferredSize();
      r.setSize(new Dimension(d.width, r.height));
      if (r.contains(me.getX(), me.getY())) {
        // if (file == null && System.getProperty("java.version").startsWith("1.7.0")) {
        //   System.out.println("XXX: Java 7, only on first run\n" + getBounds());
        //   setBounds(new Rectangle(0, 0, d.width, r.height));
        // }
        return true;
      }
    }
    return false;
  }

  @Override public void updateUI() {
    super.updateUI();
    if (panel != null) {
      panel.updateUI();
    }
    // 1.6.0_24 bug??? @see 1.7.0 DefaultTreeCellRenderer#updateUI()
    renderer = new DefaultTreeCellRenderer();
  }
// ...

References

2011/07/29

Pause and Resume SwingWorker

Code

class RunAction extends AbstractAction {
  public RunAction() {
    super("run");
  }

  @Override public void actionPerformed(ActionEvent evt) {
    JProgressBar bar1 = new JProgressBar(0, 100);
    JProgressBar bar2 = new JProgressBar(0, 100);
    runButton.setEnabled(false);
    canButton.setEnabled(true);
    pauseButton.setEnabled(true);
    statusPanel.removeAll();
    statusPanel.add(bar1, BorderLayout.NORTH);
    statusPanel.add(bar2, BorderLayout.SOUTH);
    statusPanel.revalidate();
    worker = new SwingWorker<String, Progress>() {
      private final Random r = new Random();
      @Override public String doInBackground() {
        int current = 0;
        int lengthOfTask = 12; //filelist.size();
        publish(new Progress(Component.LOG, "Length Of Task: " + lengthOfTask));
        publish(new Progress(Component.LOG, "\n---------------------------\n"));
        while (current < lengthOfTask && !isCancelled()) {
          publish(new Progress(Component.LOG, "*"));
          if (!bar1.isDisplayable()) {
            return "Disposed";
          }
          try {
            convertFileToSomething();
          } catch (InterruptedException ie) {
            return "Interrupted";
          }
          publish(new Progress(Component.TOTAL, 100 * current / lengthOfTask));
          current++;
        }
        publish(new Progress(Component.LOG, "\n"));
        return "Done";
      }

      private void convertFileToSomething() throws InterruptedException {
        boolean flag = false;
        int current = 0;
        int lengthOfTask = 10 + r.nextInt(50);
        while (current <= lengthOfTask && !isCancelled()) {
          if (isPaused) {
            try {
              Thread.sleep(500);
            } catch (InterruptedException ie) {
              return;
            }
            publish(new Progress(Component.PAUSE, flag));
            flag ^= true;
            continue;
          }
          int iv = 100 * current / lengthOfTask;
          Thread.sleep(20);
          publish(new Progress(Component.FILE, iv + 1));
          current++;
        }
      }

      @Override protected void process(java.util.List<Progress> chunks) {
        for (Progress s: chunks) {
          switch (s.component) {
            case TOTAL: bar1.setValue((Integer) s.value); break;
            case FILE:  bar2.setValue((Integer) s.value); break;
            case LOG:   area.append((String) s.value); break;
            case PAUSE: {
              if ((Boolean) s.value) {
                area.append("*");
              } else {
                try {
                  Document doc = area.getDocument();
                  doc.remove(doc.getLength() - 1, 1);
                } catch (Exception ex) {
                  ex.printStackTrace();
                }
              }
              break;
            }
          }
        }
      }

      @Override public void done() {
        // ...
      }
    };
    worker.execute();
  }
}

// ...
private boolean isPaused = false;
class PauseAction extends AbstractAction {
  public PauseAction() {
    super("pause");
  }

  @Override public void actionPerformed(ActionEvent evt) {
    isPaused = (worker != null && !worker.isCancelled() && !isPaused);
    JButton b = (JButton) evt.getSource();
    b.setText(isPaused ? "resume" : "pause");
  }
}

References

2011/06/27

Gradient translucent track JSlider

Code

UIManager.put("Slider.horizontalThumbIcon", new Icon() {
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {}
  @Override public int getIconWidth()  { return 15; }
  @Override public int getIconHeight() { return 64; }
});
UIManager.put("Slider.trackWidth", 64);
UIManager.put("Slider.majorTickLength", 6);

JSlider slider = makeSlider();
slider.setUI(new MetalSliderUI() {
  int[] pallet = makeGradientPallet();
  @Override public void paintTrack(Graphics g) {
    // Color trackColor = !slider.isEnabled()
    //   ? MetalLookAndFeel.getControlShadow() : slider.getForeground();
    boolean leftToRight = true; //MetalUtils.isLeftToRight(slider);
    Color controlDarkShadow = Color.GRAY;
    Color controlHighlight = new Color(200, 255, 200);
    Color controlShadow = new Color(0, 100, 0);

    g.translate(trackRect.x, trackRect.y);

    int trackLeft = 0;
    int trackTop = 0;
    int trackRight = 0;
    int trackBottom = 0;

    // Draw the track
    if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
      trackBottom = (trackRect.height - 1) - getThumbOverhang();
      trackTop = trackBottom - (getTrackWidth() - 1);
      trackRight = trackRect.width - 1;
    } else {
      if (leftToRight) {
        trackLeft = (trackRect.width - getThumbOverhang()) - getTrackWidth();
        trackRight = (trackRect.width - getThumbOverhang()) - 1;
      } else {
        trackLeft = getThumbOverhang();
        trackRight = getThumbOverhang() + getTrackWidth() - 1;
      }
      trackBottom = trackRect.height - 1;
    }

    if (slider.isEnabled()) {
      g.setColor(controlDarkShadow);
      g.drawRect(trackLeft, trackTop,
                (trackRight - trackLeft) - 1, (trackBottom - trackTop) - 1);

      g.setColor(controlHighlight);
      g.drawLine(trackLeft + 1, trackBottom, trackRight, trackBottom);
      g.drawLine(trackRight, trackTop + 1, trackRight, trackBottom);

      g.setColor(controlShadow);
      g.drawLine(trackLeft + 1, trackTop + 1, trackRight - 2, trackTop + 1);
      g.drawLine(trackLeft + 1, trackTop + 1, trackLeft + 1, trackBottom - 2);
    } else {
      g.setColor(controlShadow);
      g.drawRect(trackLeft, trackTop,
                 (trackRight - trackLeft) - 1, (trackBottom - trackTop) - 1);
    }

    // Draw the fill
    int middleOfThumb = 0;
    int fillTop = 0;
    int fillLeft = 0;
    int fillBottom = 0;
    int fillRight = 0;

    if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
      middleOfThumb = thumbRect.x + (thumbRect.width / 2);
      middleOfThumb -= trackRect.x; // To compensate for the g.translate()
      fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
      fillBottom = !slider.isEnabled() ? trackBottom - 1 : trackBottom - 2;

      if (!drawInverted()) {
        fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
        fillRight = middleOfThumb;
      } else {
        fillLeft = middleOfThumb;
        fillRight = !slider.isEnabled() ? trackRight - 1 : trackRight - 2;
      }
    } else {
      middleOfThumb = thumbRect.y + (thumbRect.height / 2);
      middleOfThumb -= trackRect.y; // To compensate for the g.translate()
      fillLeft = !slider.isEnabled() ? trackLeft : trackLeft + 1;
      fillRight = !slider.isEnabled() ? trackRight - 1 : trackRight - 2;

      if (!drawInverted()) {
        fillTop = middleOfThumb;
        fillBottom = !slider.isEnabled() ? trackBottom - 1 : trackBottom - 2;
      } else {
        fillTop = !slider.isEnabled() ? trackTop : trackTop + 1;
        fillBottom = middleOfThumb;
      }
    }

    if (slider.isEnabled()) {
      g.setColor(slider.getBackground());
      g.drawLine(fillLeft, fillTop, fillRight, fillTop );
      g.drawLine(fillLeft, fillTop, fillLeft, fillBottom );

      double x = (fillRight - fillLeft) / (double) (trackRight - trackLeft);
      g.setColor(getColorFromPallet(pallet, x));
      g.fillRect(fillLeft + 1, fillTop + 1,
                 fillRight - fillLeft, fillBottom - fillTop);
    } else {
      g.setColor(controlShadow);
      g.fillRect(fillLeft, fillTop, fillRight - fillLeft, trackBottom - trackTop);
    }

    int yy = trackTop + (trackBottom - trackTop) / 2;
    for (int i = 10; i >= 0; i--) {
      g.setColor(new Color(1f, 1f, 1f, i * .07f));
      g.drawLine(trackLeft + 2, yy, (trackRight - trackLeft), yy);
      yy--;
    }
    g.translate(-trackRect.x, -trackRect.y);
  }
});

// ...
private static int[] makeGradientPallet() {
  BufferedImage image = new BufferedImage(100, 1, BufferedImage.TYPE_INT_RGB);
  Graphics2D g2  = image.createGraphics();
  Point2D start  = new Point2D.Float(0f, 0f);
  Point2D end    = new Point2D.Float(99f, 0f);
  float[] dist   = {0f, .5f, 1f};
  Color[] colors = {Color.RED, Color.YELLOW, Color.GREEN};
  g2.setPaint(new LinearGradientPaint(start, end, dist, colors));
  g2.fillRect(0, 0, 100, 1);
  int width  = image.getWidth(null);
  int[] pallet = new int[width];
  PixelGrabber pg = new PixelGrabber(image, 0, 0, width, 1, pallet, 0, width);
  try {
    pg.grabPixels();
  } catch (Exception e) {
    e.printStackTrace();
  }
  return pallet;
}

private static Color getColorFromPallet(int[] pallet, float x) {
  int i = (int) (pallet.length * x);
  int max = pallet.length-1;
  int index = i < 0 ? 0 : i > max ? max : i;
  int pix = pallet[index] & 0x00_FF_FF_FF | (0x64 << 24);
  return new Color(pix, true);
}

References

2011/05/30

Translucent image caption using JTextArea, OverlayLayout, EaseInOut

Code

private int delay = 4;
private int count = 0;

@Override public void mouseEntered(MouseEvent e) {
  if (animator != null && animator.isRunning() || yy == textArea.getPreferredSize().height) {
    return;
  }
  double h = (double) textArea.getPreferredSize().height;
  animator = new Timer(delay, new ActionListener() {
    @Override public void actionPerformed(ActionEvent e) {
      double a = easeInOut(++count / h);
      yy = (int) (.5 + a * h);
      textArea.setBackground(new Color(0f, 0f, 0f, (float) (.6 * a)));
      if (yy >= textArea.getPreferredSize().height) {
        yy = textArea.getPreferredSize().height;
        animator.stop();
      }
      revalidate();
      repaint();
    }
  });
  animator.start();
}

@Override public void mouseExited(MouseEvent e) {
  if (animator != null && animator.isRunning() ||
     contains(e.getPoint()) && yy == textArea.getPreferredSize().height) return;
  double h = (double) textArea.getPreferredSize().height;
  animator = new Timer(delay, new ActionListener() {
    @Override public void actionPerformed(ActionEvent e) {
      double a = easeInOut(--count / h);
      yy = (int) (.5 + a * h);
      textArea.setBackground(new Color(0f, 0f, 0f, (float) (.6 * a)));
      if (yy <= 0) {
        yy = 0;
        animator.stop();
      }
      revalidate();
      repaint();
    }
  });
  animator.start();
}

// @see Math: EaseIn EaseOut, EaseInOut and BeziƩr Curves | Anima Entertainment GmbH
// http://www.anima-entertainment.de/math-easein-easeout-easeinout-and-bezier-curves
public double easeInOut(double t) {
  // range: 0.0 <= t <= 1.0
  if (t < .5) {
    return .5 * Math.pow(t * 2d, 3d);
  } else {
    return .5 * (Math.pow(t * 2d - 2d, 3d) + 2d);
  }
}

public static double intpow(double x, int n) {
  double aux = 1d;
  if (n < 0) {
    throw new IllegalArgumentException("n must be a positive integer");
  }
  for (; n > 0; x *= x, n >>>= 1) {
    if ((n & 1) != 0) {
      aux *= x;
    }
  }
  return aux;
}

References

2011/05/24

Change border of focused row in JTable

Code

enum Type { START, END }

class DotBorder extends EmptyBorder {
  private static final BasicStroke DASHED = new BasicStroke(
      1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
      10f, new float[] {1f}, 0f);
  private static final Color DOT_COLOR = new Color(200, 150, 150);
  public final Set<Type> type = EnumSet.noneOf(Type.class);

  protected DotBorder(int top, int left, int bottom, int right) {
    super(top, left, bottom, right);
  }

  @Override public boolean isBorderOpaque() {
    return true;
  }

  @Override public void paintBorder(
      Component c, Graphics g, int x, int y, int w, int h) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.translate(x, y);
    g2.setPaint(DOT_COLOR);
    g2.setStroke(DASHED);
    if (type.contains(Type.START)) {
      g2.drawLine(0, 0, 0, h);
    }
    if (type.contains(Type.END)) {
      g2.drawLine(w - 1, 0, w - 1, h);
    }
    if (c.getBounds().x % 2 == 0) {
      g2.drawLine(0, 0, w, 0);
      g2.drawLine(0, h - 1, w, h - 1);
    } else {
      g2.drawLine(1, 0, w, 0);
      g2.drawLine(1, h - 1, w, h - 1);
    }
    g2.dispose();
  }
}

References