package gov.nasa.arc.mct.fastplot.view.legend;
import gov.nasa.arc.mct.components.AbstractComponent;
import gov.nasa.arc.mct.components.FeedProvider;
import gov.nasa.arc.mct.components.FeedProvider.RenderingInfo;
import gov.nasa.arc.mct.fastplot.bridge.AbstractPlotLine;
import gov.nasa.arc.mct.gui.View;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.fest.swing.core.BasicRobot;
import org.fest.swing.core.ComponentDragAndDrop;
import org.fest.swing.core.Robot;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class TestLegendEntryView {
private static final String TEST_ID = "test:id";
private static final String TEST_NAME = "Test component";
private static final String OTHER_NAME = "Supplied name";
private static final Color TEST_COLOR = Color.PINK;
@Mock AbstractComponent comp;
@Mock FeedProvider fp;
@Mock RenderingInfo ri;
LegendEntryView view;
JFrame f;
@BeforeClass
public void setupFrame() {
f = new JFrame();
f.setVisible(true);
}
@BeforeMethod
public void setup() {
MockitoAnnotations.initMocks(this);
Mockito.when(comp.getDisplayName()).thenReturn(TEST_NAME);
Mockito.when(comp.getCapability(FeedProvider.class)).thenReturn(fp);
Mockito.when(fp.getRenderingInfo(Mockito.anyMap())).thenReturn(ri);
Mockito.when(fp.getSubscriptionId()).thenReturn(TEST_ID);
Mockito.when(ri.getStatusText()).thenReturn("");
Mockito.when(ri.isPlottable()).thenReturn(true);
view = new LegendEntryView(comp, LegendEntryView.VIEW_INFO);
f.getContentPane().removeAll();
f.getContentPane().add(view);
f.pack();
}
@AfterClass
public void tearDown() {
f.setVisible(false);
f.dispose();
}
@Test
public void testComponentName() {
Assert.assertEquals(view.getDisplayedName(), TEST_NAME);
view.setBaseDisplayName(OTHER_NAME);
Assert.assertEquals(view.getDisplayedName(), OTHER_NAME);
}
@Test
public void testSetAppearanceColor() {
Assert.assertFalse(containsColor(drawComponent(view), TEST_COLOR));
view.setAppearance(TEST_COLOR, null);
Assert.assertTrue (containsColor(drawComponent(view), TEST_COLOR));
}
@Test
public void testAttachPlotLine() {
// Attaching a plot line should update the color of the legend to match
AbstractPlotLine mockPlotLine = Mockito.mock(AbstractPlotLine.class);
Mockito.when(mockPlotLine.getColor()).thenReturn(TEST_COLOR);
Assert.assertFalse(containsColor(drawComponent(view), TEST_COLOR));
view.attachPlotLine(mockPlotLine);
Assert.assertTrue (containsColor(drawComponent(view), TEST_COLOR));
}
@Test
public void testShowsStatus() {
// Draw the same view with multiple rendering infos; confirm they are all drawn uniquely
List<BufferedImage> images = new ArrayList<BufferedImage>();
Map<String, List<Map<String,String>>> data = new HashMap<String,List<Map<String,String>>>();
List<Map<String,String>> points = new ArrayList<Map<String,String>>();
points.add(new HashMap<String,String>()); // Rendering info, which is mocked, should decode this, so empty map should be fine
data.put(TEST_ID, points);
for (boolean plottable : new boolean[]{true,false}) {
for (String status : new String[]{"", "A", "B"}) {
Mockito.when(ri.isPlottable()).thenReturn(plottable);
Mockito.when(ri.getStatusText()).thenReturn(status);
view.updateFromFeed(data);
images.add(drawComponent(view));
}
}
for (int i = 0; i < images.size(); i++) {
for (int j = i + 1; j < images.size(); j++) {
Assert.assertFalse(imagesEqual(images.get(i), images.get(j)));
}
}
Assert.assertTrue(imagesEqual(images.get(0), images.get(0)));
}
@Test
public void testVisibleFeedProviders() {
Assert.assertTrue(view.getVisibleFeedProviders().contains(fp));
}
@Test
public void testDragAndDrop() {
TestDropTarget dt = new TestDropTarget();
f.getContentPane().removeAll();
JPanel dest = new JPanel(); // Drop target
dest.setBackground(Color.YELLOW);
dest.setDropTarget(dt);
JPanel p = new JPanel(new BorderLayout());
p.add(view, BorderLayout.NORTH);
p.add(dest, BorderLayout.CENTER);
f.getContentPane().add(p);
f.pack();
Assert.assertNull(dt.v); // Make sure we're starting clean
Robot robot = BasicRobot.robotWithCurrentAwtHierarchy();
ComponentDragAndDrop d = new ComponentDragAndDrop(robot);
d.drag(view, new Point(5,5));
d.drop(view, new Point(5,5));
Assert.assertNull(dt.v); // Nothing should have happened
d.drag(view, new Point(5,5));
d.drop(dest, new Point(5,5));
Assert.assertEquals(dt.v, view); // Make sure the right view got dropped
}
// Test disabled pending alternative approach (open is final, can't be mocked)
@Test (enabled = false)
public void testDoubleClick() {
Robot robot = BasicRobot.robotWithCurrentAwtHierarchy();
Mockito.verify(comp, Mockito.never()).open();
robot.doubleClick(view);
Mockito.verify(comp, Mockito.times(1)).open();
}
@Test (enabled = false)
public void testSetAppearanceIcon() {
}
private BufferedImage drawComponent(final JComponent comp) {
final BufferedImage img = new BufferedImage(comp.getWidth(), comp.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
comp.paint(img.createGraphics());
}
});
} catch (InterruptedException e) {
Assert.fail(); // We need to paint to verify, so fail if we can't
} catch (InvocationTargetException e) {
Assert.fail(); // We need to paint to verify, so fail if we can't
}
return img;
}
private boolean imagesEqual(BufferedImage a, BufferedImage b) {
if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
return false;
}
for (int y = 0; y < a.getHeight(); y++) {
for (int x = 0; x < a.getWidth(); x++) {
if (a.getRGB(x, y) != b.getRGB(x, y)) return false;
}
}
return true;
}
private boolean containsColor(BufferedImage im, Color c) {
for (int y = 0; y < im.getHeight(); y++) {
for (int x = 0; x < im.getWidth(); x++) {
int rgb = im.getRGB(x, y);
int r = ((rgb & 0xFF0000) >> 16) - c.getRed();
int g = ((rgb & 0x00FF00) >> 8) - c.getGreen();
int b = ((rgb & 0x0000FF) >> 0) - c.getBlue();
if (r < 4 && g < 4 && b < 4 &&
r > -4 && g > -4 && b > -4) { // Give some leeway, since font may be antialiased
return true;
}
}
}
return false;
}
private static class TestDropTarget extends DropTarget {
private static final long serialVersionUID = -7167420468257291174L;
public View v = null;
public void drop (DropTargetDropEvent event) {
if (event.getTransferable().isDataFlavorSupported(View.DATA_FLAVOR)) {
try {
for (View view : (View[]) event.getTransferable().getTransferData(View.DATA_FLAVOR)) {
v = view;
break; // Only take the first!
}
} catch (UnsupportedFlavorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}