package org.lobobrowser.security;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.plaf.basic.BasicButtonUI;
import org.lobobrowser.security.PermissionSystem.Permission;
import org.lobobrowser.security.PermissionSystem.PermissionBoard.PermissionRow.PermissionCell;
import org.lobobrowser.security.PermissionSystem.PermissionResult;
public class PermissionCellButton extends JButton implements MouseMotionListener {
@FunctionalInterface
public static interface ChangeListener {
public void onChange();
}
private final PermissionCell cell;
private PermissionResult permissionResult;
private final ChangeListener cellChangeListener;
private final boolean canBeUndecidable;
private static final int BORDER_PADDING = 2;
private static final Color GREY_TRANSPARENT = new Color(.3f, .3f, .3f, .5f);
private static final Color WHITE = new Color(1f, 1f, 1f, 1f);
private static final Color RED_TRANSPARENT = new Color(1f, .2f, .2f, .51f);
private static final Color GREEN_TRANSPARENT = new Color(.2f, 1f, .2f, .51f);
private static final Color RED_OPAQUE = new Color(1f, .4f, .4f, 1f);
private static final Color GREEN_OPAQUE = new Color(.2f, 1f, .2f, 1f);
private static final Color LIGHT_RED_OPAQUE = new Color(1f, .8f, .8f, 1f);
private static final Color LIGHT_GREEN_OPAQUE = new Color(.8f, 1f, .8f, 1f);
private static final long serialVersionUID = 1L;
// private final CompoundBorder redCompoundBorder, greenCompoundBorder;
// private final Border defaultBorder;
public static Insets grow(final Insets in, final int amount) {
final Insets out = new Insets(in.top + amount, in.left + amount, in.bottom + amount, in.right + amount);
return out;
}
public PermissionCellButton(final PermissionCell cell, final String text, final boolean alignRight, final ChangeListener changeListener) {
super(text);
this.cell = cell;
this.canBeUndecidable = cell.canBeUndecidable;
this.cellChangeListener = changeListener;
// final Border defaultBorder = getBorder();
final Insets marginInsets = getMargin();
final Insets borderInsets = grow(marginInsets, BORDER_PADDING);
final Border emptyBorder =
BorderFactory
.createEmptyBorder(borderInsets.top, borderInsets.left, borderInsets.bottom, borderInsets.right);
final Border defaultColorBorder = BorderFactory.createDashedBorder(GREY_TRANSPARENT);
final CompoundBorder plainBorder = BorderFactory.createCompoundBorder(defaultColorBorder, emptyBorder);
setBorder(plainBorder);
permissionResult = cell.getEffectivePermission();
assert (permissionResult.permission.isDecided());
setHorizontalAlignment(alignRight ? SwingConstants.RIGHT : SwingConstants.CENTER);
setUI(new BasicButtonUI());
addMouseMotionListener(this);
setFocusable(false);
setForeground(Color.BLACK);
updateBackground();
}
private void updateBackground() {
final boolean isDefault = permissionResult.isDefault;
switch (permissionResult.permission) {
case Allow:
setBackground(isDefault ? LIGHT_GREEN_OPAQUE : GREEN_OPAQUE);
break;
case Deny:
setBackground(isDefault ? LIGHT_RED_OPAQUE : RED_OPAQUE);
break;
case Undecided:
throw new RuntimeException("Unexpected undecided state");
}
/*
* if (state.isKnownState()) { switch (defaultState) { case Disabled:
* setBorder(redCompoundBorder); break; case Enabled:
* setBorder(greenCompoundBorder); break; case Default: throw new
* RuntimeException("Unexpected default state"); } } else {
* setBorder(defaultBorder); }
*/
}
@Override
protected void paintComponent(final Graphics g) {
final Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
if (mouseIn) {
if (permissionResult.isDefault || !canBeUndecidable) {
g.setColor(mouseOnLeft ? RED_TRANSPARENT : GREEN_TRANSPARENT);
final int leftEdge = mouseOnLeft ? 0 : getWidth() / 2;
final int rightEdge = mouseOnLeft ? getWidth() / 2 : getWidth();
g.fillRect(leftEdge, 0, rightEdge, getHeight());
} else {
g.setColor(WHITE);
final int leftX = 6;
final int topY = 6;
final int rightX = 12;
final int bottomY = 12;
g2.setStroke(new BasicStroke(2));
g.drawLine(leftX, topY, rightX, bottomY);
g.drawLine(leftX, bottomY, rightX, topY);
}
}
}
private boolean mouseIn = false;
private boolean mouseOnLeft = false;
@Override
public void mouseDragged(final MouseEvent e) {
}
@Override
public void mouseMoved(final MouseEvent e) {
// System.out.println(String.format("%5d, %5d : %s", e.getX(),
// e.getY(), e));
final boolean prevMouseOnLeft = mouseOnLeft;
mouseOnLeft = e.getX() < (getWidth() / 2);
if (mouseOnLeft != prevMouseOnLeft) {
repaint();
}
}
@Override
protected void processMouseEvent(final MouseEvent e) {
super.processMouseEvent(e);
if (e.getID() == MouseEvent.MOUSE_ENTERED) {
mouseIn = true;
repaint();
} else if (e.getID() == MouseEvent.MOUSE_EXITED) {
mouseIn = false;
repaint();
} else if (e.getID() == MouseEvent.MOUSE_CLICKED) {
assert (mouseIn);
if (!permissionResult.isDefault && canBeUndecidable) {
cell.setPermission(Permission.Undecided);
} else {
if (mouseOnLeft) {
cell.setPermission(Permission.Deny);
} else {
cell.setPermission(Permission.Allow);
}
}
cellChangeListener.onChange();
} else {
// System.out.println("Mouse event:" + e);
}
}
public void update() {
permissionResult = cell.getEffectivePermission();
updateBackground();
}
}