package net.sourceforge.pmd.eclipse.ui; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; /** * Renders a set of coloured shapes mapped to known set of incoming items * * @author Brian Remedios */ public class ShapePicker<T extends Object> extends Canvas implements ISelectionProvider { private T[] items; private int itemWidth; private int gap = 6; private T selectedItem; private T highlightItem; private Color selectedItemFillColor; private LabelProvider tooltipProvider; private Map<T, ShapeDescriptor> shapeDescriptorsByItem; // private Map<T, String> tooltipsByItem; private List<ISelectionChangedListener> listeners; private static Map<RGB, Color> coloursByRGB = new HashMap<RGB, Color>(); public ShapePicker(Composite parent, int style, int theItemWidth) { super(parent, style); itemWidth = theItemWidth; ShapePicker.this.addPaintListener( new PaintListener() { public void paintControl(PaintEvent pe) { doPaint(pe); } } ); ShapePicker.this.addMouseMoveListener( new MouseMoveListener() { public void mouseMove(MouseEvent e) { if (!getEnabled()) return; T newItem = itemAt(e.x, e.y); if (newItem != highlightItem) { highlightItem = newItem; setToolTipText( tooltipFor(newItem) ); redraw(); } } } ); ShapePicker.this.addMouseListener( new MouseListener() { public void mouseDoubleClick(MouseEvent e) { } public void mouseDown(MouseEvent e) { forceFocus(); } public void mouseUp(MouseEvent e) { if (!getEnabled()) return; T newItem = itemAt(e.x, e.y); if (newItem != selectedItem) { selectedItem = newItem; redraw(); selectionChanged(); } } } ); ShapePicker.this.addFocusListener( new FocusListener() { public void focusGained(FocusEvent e) { redraw(); } public void focusLost(FocusEvent e) { redraw(); } } ); selectedItemFillColor = colorFor(new RGB(200,200,200)); } private Color colourFor(int itemIndex) { ShapeDescriptor desc = shapeDescriptorsByItem.get(items[itemIndex]); if (desc == null) return Display.getCurrent().getSystemColor(SWT.COLOR_BLACK); RGB rgb = desc.rgbColor; return colorFor(rgb); } private String tooltipFor(T item) { return item == null ? "" : tooltipProvider == null ? item.toString() : tooltipProvider.labelFor(item); } private Color colorFor(RGB rgb) { Color color = coloursByRGB.get(rgb); if (color != null) return color; color = new Color(null, rgb.red, rgb.green, rgb.blue); coloursByRGB.put( rgb, color ); return color; } private void selectionChanged() { if (listeners == null) return; IStructuredSelection selection = new StructuredSelection( new Object[] { selectedItem } ); SelectionChangedEvent event = new SelectionChangedEvent(this, selection); for (ISelectionChangedListener listener : listeners) { listener.selectionChanged(event); } } public boolean forceFocus() { boolean state = super.forceFocus(); redraw(); return state; } private Shape shapeFor(int itemIndex) { ShapeDescriptor desc = shapeDescriptorsByItem.get(items[itemIndex]); return desc == null ? Shape.circle : desc.shape; } private T itemAt(int xIn, int yIn) { if (items == null) return null; int width = getSize().x; int xBoundary = 3; for (int i=0; i<items.length; i++) { int xOffset = 0; int step = (itemWidth + gap) * i; switch (SWT.LEFT) { // TODO take from style bits case SWT.CENTER: xOffset = (width / 2) - (itemWidth / 2) - xBoundary + step; break; case SWT.RIGHT: xOffset = 0 - xBoundary; break; case SWT.LEFT: xOffset = xBoundary + step; } if (xIn < xOffset ) { return items[ i == 0 ? 0 : i-1 ]; } if (xIn < xOffset + itemWidth) return items[i]; } return null; } private void doPaint(PaintEvent pe) { if (items == null) return; GC gc = pe.gc; int width = getSize().x; int xBoundary = 3; if (isFocusControl()) { gc.drawFocus(0,0, getSize().x, getSize().y); } for (int i=0; i<items.length; i++) { gc.setBackground( selectedItem == items[i] ? selectedItemFillColor : colourFor(i)); int xOffset = 0; int step = (itemWidth + gap) * i; switch (SWT.LEFT) { // TODO take from style bits case SWT.CENTER: xOffset = (width / 2) - (itemWidth / 2) - xBoundary + step; break; case SWT.RIGHT: xOffset = 0 - xBoundary; break; case SWT.LEFT: xOffset = xBoundary + step; } gc.setLineWidth( showHighlightOn(items[i]) ? 3 : 1); ShapePainter.drawShape(itemWidth, itemWidth, shapeFor(i), gc, pe.x + xOffset, pe.y + gap, null); } } private boolean showHighlightOn(T item) { return isFocusControl() && highlightItem == item; } public Point computeSize(int wHint, int hHint, boolean changed) { Point pt = getSize(); // TODO adapt by shape count return new Point(pt.x, pt.y); } public void setSelection(T item) { selectedItem = item; redraw(); selectionChanged(); } public void tooltipProvider(LabelProvider provider) { tooltipProvider = provider; } public ISelection getSelection() { return new StructuredSelection(selectedItem); } public void setGap(int inPixels) { gap = inPixels; redraw(); } public void setItems(T[] theItems) { items = theItems; redraw(); } public void setItemWidth(int width) { itemWidth = width; redraw(); } public void setShapeMap(Map<T, ShapeDescriptor> theShapeMap) { shapeDescriptorsByItem = theShapeMap; redraw(); } public void addSelectionChangedListener(ISelectionChangedListener listener) { if (listeners == null) listeners = new Vector<ISelectionChangedListener>(); listeners.add(listener); } public void removeSelectionChangedListener(ISelectionChangedListener listener) { if (listeners == null) return; listeners.remove(listener); } public void setSelection(ISelection selection) { setSelection( (T)((StructuredSelection)selection).getFirstElement() ); } // public void setTooltipMap(Map<T, String> theTooltips) { // tooltipsByItem = theTooltips; // } }