package net.sourceforge.pmd.eclipse.util; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.eclipse.ui.Shape; import net.sourceforge.pmd.eclipse.ui.ShapePainter; import net.sourceforge.pmd.eclipse.ui.preferences.br.CellPainterBuilder; import net.sourceforge.pmd.eclipse.ui.preferences.br.RuleFieldAccessor; import net.sourceforge.pmd.util.ClassUtil; import net.sourceforge.pmd.util.StringUtil; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.Region; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; public class Util { public static final Object[] EMPTY_ARRAY = new Object[0]; public static final Comparator<Method> MethodNameComparator = new Comparator<Method>() { public int compare(Method a, Method b) { return a.getName().compareTo(b.getName()); } }; public static final Comparator<String> compStr = new Comparator<String>() { public int compare(String a, String b) { return a.compareTo(b); } }; public static final Comparator<Integer> compInt = new Comparator<Integer>() { public int compare(Integer a, Integer b) { return a.compareTo(b); } }; public static final Comparator<Long> compLong = new Comparator<Long>() { public int compare(Long a, Long b) { return a.compareTo(b); } }; public static final Comparator<Float> compFloat = new Comparator<Float>() { public int compare(Float a, Float b) { return a.compareTo(b); } }; public static final Comparator<Boolean> compBool= new Comparator<Boolean>() { public int compare(Boolean a, Boolean b) { return a.compareTo(b); } }; public static final Comparator<Date> compDate = new Comparator<Date>() { public int compare(Date a, Date b) { return a.compareTo(b); } }; public static final Comparator<Character> compChr = new Comparator<Character>() { public int compare(Character a, Character b) { return a.compareTo(b); } }; private Util() {}; /** * Scans the source for occurrences of the prefix char and assumes that all letters * that follow immediately after make up a reference name. Returns the position and * lengths of all names found. * * NOTE: Doesn't handle the prefix within escaped or quoted strings * * @param source * @param prefix * @return List<int[]> */ public static List<int[]> referencedNamePositionsIn(String source, char prefix) { List<int[]> namePositions = new ArrayList<int[]>(); if (StringUtil.isEmpty(source)) return namePositions; int pos = source.indexOf(prefix); int max = source.length(); while (pos >= 0) { int end = pos+1; while (end < max && Character.isLetter(source.charAt(end)) ) end++; int length = end - pos -1; if (length < 1) { pos = source.indexOf(prefix, pos + 1); continue; } namePositions.add( new int[] {pos+1, length} ); pos = source.indexOf(prefix, pos + length); } return namePositions; } /** * Extract and return all the string fragments listed in the list of positions * where each position = int [start][length] * * @param source * @param positions * @return List<String> */ public static List<String> fragmentsWithin(String source, List<int[]> positions) { List<String> fragments = new ArrayList<String>(positions.size()); for (int[] position : positions) { fragments.add( source.substring(position[0], position[0] + position[1]) ); } return fragments; } public static String signatureFor(Method method, String[] unwantedPrefixes) { StringBuilder sb = new StringBuilder(); Class<?> returnType = method.getReturnType(); if (returnType.getName().equals("void")) { // TODO is there a better way? sb.append("void "); } else { signatureFor(returnType, unwantedPrefixes, sb); sb.append(' '); } Class<?>[] types = method.getParameterTypes(); if (types.length == 0) { sb.append(method.getName()); sb.append("()"); return sb.toString(); } sb.append(method.getName()).append('('); signatureFor(types[0], unwantedPrefixes, sb); for (int i=1; i<types.length; i++) { sb.append(','); signatureFor(types[i], unwantedPrefixes, sb); } sb.append(')'); return sb.toString(); } private static String filteredPrefixFrom(String paramType, String[] unwantedPrefixes) { for (String prefix : unwantedPrefixes) { if (paramType.startsWith(prefix)) { return paramType.substring(prefix.length()); } } return paramType; } public static String signatureFor(Class<?> type, String[] unwantedPrefixes) { StringBuilder sb = new StringBuilder(); signatureFor(type, unwantedPrefixes, sb); return sb.toString(); } private static void signatureFor(Class<?> type, String[] unwantedPrefixes, StringBuilder sb) { String typeName = ClassUtil.asShortestName( type.isArray() ? type.getComponentType() : type ); typeName = filteredPrefixFrom(typeName, unwantedPrefixes); sb.append(typeName); if (type.isArray()) sb.append("[]"); } public static Comparator<?> comparatorFrom(final RuleFieldAccessor accessor, final boolean inverted) { if (accessor == null) { throw new IllegalArgumentException("Accessor is required"); } return new Comparator<Rule>() { public int compare(Rule a, Rule b) { Comparable ca = accessor.valueFor(a); Comparable cb = accessor.valueFor(b); int result = (ca == null) ? -1 : (cb == null) ? 1 : ca.compareTo(cb); return inverted ? result * -1 : result; } }; } public static void removeListeners(Control widget, int listenerType) { for (Listener listener : widget.getListeners(listenerType)) { widget.removeListener(listenerType, listener); } } public static int indexOf(Object[] items, Object choice) { for (int i=0; i<items.length; i++) { if (items[i].equals(choice)) return i; } return -1; } /** * Method asCleanString. * @param original String * @return String */ public static String asCleanString(String original) { return original == null ? "" : original.trim(); } public static CellPainterBuilder itemAsShapeFor(final int width, final int height, final Shape shapeId, final int horizAlignment, final Map<Object, RGB> coloursByItem) { return new AbstractCellPainterBuilder() { private Color getterColorIn(TreeItem tItem, RuleFieldAccessor getter) { Object value = valueFor(tItem, getter); RGB color = coloursByItem.get(value); return color == null ? null : colorManager().colourFor(color); } public void addPainterFor(final Tree tree, final int columnIndex, final RuleFieldAccessor getter, Map<Integer, List<Listener>> listenersByEventCode) { final int xBoundary = 3; Listener paintListener = new Listener() { public void handleEvent(Event event) { if (event.index != columnIndex) return; Color clr = getterColorIn((TreeItem)event.item, getter); if (clr == null) return; Color original = event.gc.getBackground(); event.gc.setBackground(clr); int xOffset = 0; final int cellWidth = widthOf(columnIndex, tree); switch (horizAlignment) { case SWT.CENTER: xOffset = (cellWidth / 2) - (width / 2) - xBoundary; break; case SWT.RIGHT: xOffset = cellWidth - width - xBoundary; break; case SWT.LEFT: xOffset = 0; } ShapePainter.drawShape(width, height, shapeId, event.gc, event.x + xOffset, event.y, null); event.gc.setBackground(original); } }; Listener measureListener = new Listener() { public void handleEvent(Event e) { if (e.index != columnIndex) return; e.width = width ; e.height = height ; } }; addListener(tree, SWT.PaintItem, paintListener, listenersByEventCode); addListener(tree, SWT.MeasureItem, measureListener, listenersByEventCode); } }; } public static void addListener(Control control, int eventType, Listener listener, Map<Integer, List<Listener>> listenersByEventCode) { Integer eventCode = Integer.valueOf(eventType); control.addListener(eventType, listener); if (!listenersByEventCode.containsKey(eventCode)) { listenersByEventCode.put(eventCode, new ArrayList<Listener>()); } listenersByEventCode.get(eventCode).add(listener); } public static CellPainterBuilder backgroundBuilderFor(final int systemColourIndex) { return new CellPainterBuilder() { public void addPainterFor(final Tree tree, final int columnIndex, final RuleFieldAccessor getter, Map<Integer, List<Listener>> paintListeners) { final Display display = tree.getDisplay(); tree.addListener(SWT.EraseItem, new Listener() { public void handleEvent(Event event) { if (event.index != columnIndex) return; event.detail &= ~SWT.HOT; if ((event.detail & SWT.SELECTED) != 0) { GC gc = event.gc; Rectangle area = tree.getClientArea(); /* * If you wish to paint the selection beyond the end of last column, you must change the clipping region. */ int columnCount = tree.getColumnCount(); if (event.index == columnCount - 1 || columnCount == 0) { int width = area.x + area.width - event.x; if (width > 0) { Region region = new Region(); gc.getClipping(region); region.add(event.x, event.y, width, event.height); gc.setClipping(region); region.dispose(); } } gc.setAdvanced(true); if (gc.getAdvanced()) gc.setAlpha(127); Rectangle rect = event.getBounds(); Color foreground = gc.getForeground(); Color background = gc.getBackground(); gc.setForeground(display.getSystemColor(systemColourIndex)); gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND)); gc.fillGradientRectangle(event.x, rect.y, 500, rect.height, false); gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT)); gc.drawLine(event.x, rect.y, event.x + 20, rect.y + 20); gc.setForeground(foreground); // restore colors for subsequent drawing gc.setBackground(background); event.detail &= ~SWT.SELECTED; } } }); }}; } public static CellPainterBuilder textBuilderFor(final int systemColourIndex) { return new CellPainterBuilder() { public void addPainterFor(final Tree tree, final int columnIndex, final RuleFieldAccessor getter, Map<Integer, List<Listener>> paintListeners) { // final Display display = tree.getDisplay(); // tree.addListener(SWT.EraseItem, new Listener() { // public void handleEvent(Event event) { // if (event.index != columnIndex) return; // // // GC gc = event.gc; // // Rectangle area = new Rectangle(event.x, event.y, event.width, event.height); // // // gc.fillRectangle(area); // } // // }); tree.addListener(SWT.PaintItem, new Listener() { public void handleEvent(Event event) { if (event.index != columnIndex) return; event.detail &= ~SWT.HOT; // if ((event.detail & SWT.SELECTED) != 0) { GC gc = event.gc; Rectangle area = tree.getClientArea(); Rule rule = (Rule)((TreeItem)event.item).getData(); String text = getter.valueFor(rule).toString(); int columnCount = tree.getColumnCount(); if (event.index == columnCount - 1 || columnCount == 0) { int width = area.x + area.width - event.x; if (width > 0) { Region region = new Region(); gc.getClipping(region); region.add(event.x, event.y, width, event.height); gc.setClipping(region); region.dispose(); } } // gc.setAdvanced(true); // if (gc.getAdvanced()) gc.setAlpha(127); Rectangle rect = event.getBounds(); // Color foreground = gc.getForeground(); // Color background = gc.getBackground(); // gc.setForeground(display.getSystemColor(systemColourIndex)); // gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND)); // gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT)); gc.drawString(text, event.x, rect.y); // gc.setForeground(foreground); // restore colors for subsequent drawing // gc.setBackground(background); // event.detail &= ~SWT.SELECTED; // } } }); }}; } public static String asString(List<String> items, String separator) { if (items == null || items.isEmpty()) return ""; if (items.size() == 1) return items.get(0); StringBuilder sb = new StringBuilder(items.get(0)); for (int i=1; i<items.size(); i++) { sb.append(separator).append(items.get(i)); } return sb.toString(); } public static void asString(Object[] items, String separator, StringBuilder target) { if (items == null || items.length==0) return; target.append(items[0]); for (int i=1; i<items.length; i++) { target.append(separator).append(items[i]); } } }