package com.revolsys.swing.map.layer.record.renderer; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Predicate; import com.revolsys.collection.list.Lists; import com.revolsys.collection.map.MapEx; import com.revolsys.datatype.DataType; import com.revolsys.logging.Logs; import com.revolsys.swing.map.layer.LayerRenderer; import com.revolsys.swing.map.layer.Project; import com.revolsys.swing.map.layer.record.AbstractRecordLayer; import com.revolsys.swing.map.layer.record.LayerRecord; import com.revolsys.swing.menu.MenuFactory; import com.revolsys.swing.menu.Menus; import com.revolsys.swing.tree.BaseTree; import com.revolsys.swing.tree.BaseTreeNode; import com.revolsys.util.JavaBeanUtil; import com.revolsys.util.Property; public abstract class AbstractMultipleRenderer extends AbstractRecordLayerRenderer { static { final MenuFactory menu = MenuFactory.getMenu(AbstractMultipleRenderer.class); addAddMenuItem(menu, "Geometry", GeometryStyleRenderer::new); addAddMenuItem(menu, "Text", TextStyleRenderer::new); addAddMenuItem(menu, "Marker", MarkerStyleRenderer::new); addAddMenuItem(menu, "Multiple", MultipleRenderer::new); addAddMenuItem(menu, "Filter", FilterMultipleRenderer::new); addAddMenuItem(menu, "Scale", ScaleMultipleRenderer::new); addConvertMenuItem(menu, "Multiple", MultipleRenderer.class, AbstractMultipleRenderer::convertToMultipleStyle); addConvertMenuItem(menu, "Filter", FilterMultipleRenderer.class, AbstractMultipleRenderer::convertToFilterStyle); addConvertMenuItem(menu, "Scale", ScaleMultipleRenderer.class, AbstractMultipleRenderer::convertToScaleStyle); } protected static void addAddMenuItem(final MenuFactory menu, final String type, final BiFunction<AbstractRecordLayer, AbstractMultipleRenderer, AbstractRecordLayerRenderer> rendererFactory) { final String iconName = ("style_" + type + "_add").toLowerCase(); final String name = "Add " + type + " Style"; Menus.addMenuItem(menu, "add", name, iconName, (final AbstractMultipleRenderer parentRenderer) -> { final AbstractRecordLayer layer = parentRenderer.getLayer(); final AbstractRecordLayerRenderer newRenderer = rendererFactory.apply(layer, parentRenderer); parentRenderer.addRendererEdit(newRenderer); }, false); } protected static void addConvertMenuItem(final MenuFactory menu, final String type, final Class<?> rendererClass, final Consumer<AbstractMultipleRenderer> consumer) { final String iconName = ("style_" + type + "_go").toLowerCase(); final Predicate<AbstractMultipleRenderer> enabledFilter = ( final AbstractMultipleRenderer renderer) -> { return renderer.getClass() != rendererClass; }; final String name = "Convert to " + type + " Style"; Menus.addMenuItem(menu, "convert", name, iconName, enabledFilter, consumer, false); } private List<AbstractRecordLayerRenderer> renderers = new ArrayList<>(); public AbstractMultipleRenderer(final String type, final AbstractRecordLayer layer, final LayerRenderer<?> parent) { super(type, "Styles", layer, parent); } public AbstractMultipleRenderer(final String type, final String name) { super(type, name); } public int addRenderer(final AbstractRecordLayerRenderer renderer) { return addRenderer(-1, renderer); } public int addRenderer(int index, final AbstractRecordLayerRenderer renderer) { if (renderer == null) { return -1; } else { final String originalName = renderer.getName(); String name = originalName; int i = 1; while (hasRendererWithSameName(renderer, name)) { name = originalName + i; i++; } renderer.setName(name); renderer.setParent(this); synchronized (this.renderers) { if (index < 0) { index = this.renderers.size(); } this.renderers.add(index, renderer); } firePropertyChange("renderers", index, null, renderer); return index; } } public void addRendererEdit(final AbstractRecordLayerRenderer renderer) { addRenderer(-1, renderer); final Object item = MenuFactory.getMenuSource(); if (item instanceof BaseTreeNode) { final BaseTreeNode node = (BaseTreeNode)item; final BaseTree tree = node.getTree(); if (tree.isPropertyEqual("treeType", Project.class.getName())) { final AbstractRecordLayer layer = renderer.getLayer(); layer.showRendererProperties(renderer); } } } @Override public AbstractMultipleRenderer clone() { final AbstractMultipleRenderer clone = (AbstractMultipleRenderer)super.clone(); clone.renderers = JavaBeanUtil.clone(this.renderers); for (final AbstractRecordLayerRenderer renderer : clone.renderers) { renderer.setParent(clone); } return clone; } public FilterMultipleRenderer convertToFilterStyle() { final AbstractRecordLayer layer = getLayer(); final List<AbstractRecordLayerRenderer> renderers = getRenderers(); final AbstractMultipleRenderer parent = (AbstractMultipleRenderer)getParent(); final Map<String, Object> style = toMap(); style.remove("styles"); final FilterMultipleRenderer newRenderer = new FilterMultipleRenderer(layer, parent); newRenderer.setProperties(style); newRenderer.setRenderers(JavaBeanUtil.clone(renderers)); final String name = getName(); if (name.equals("Multiple Style")) { newRenderer.setName("Filter Style"); } else if (name.equals("Scale Style")) { newRenderer.setName("Filter Style"); } replace(layer, parent, newRenderer); return newRenderer; } public MultipleRenderer convertToMultipleStyle() { final AbstractRecordLayer layer = getLayer(); final List<AbstractRecordLayerRenderer> renderers = getRenderers(); final AbstractMultipleRenderer parent = (AbstractMultipleRenderer)getParent(); final Map<String, Object> style = toMap(); style.remove("styles"); final MultipleRenderer newRenderer = new MultipleRenderer(layer, parent); newRenderer.setProperties(style); newRenderer.setRenderers(JavaBeanUtil.clone(renderers)); final String name = getName(); if (name.equals("Filter Style")) { newRenderer.setName("Multiple Style"); } else if (name.equals("Scale Style")) { newRenderer.setName("Multiple Style"); } replace(layer, parent, newRenderer); return newRenderer; } public ScaleMultipleRenderer convertToScaleStyle() { final AbstractRecordLayer layer = getLayer(); final List<AbstractRecordLayerRenderer> renderers = getRenderers(); final AbstractMultipleRenderer parent = (AbstractMultipleRenderer)getParent(); final Map<String, Object> style = toMap(); style.remove("styles"); final ScaleMultipleRenderer newRenderer = new ScaleMultipleRenderer(layer, parent); newRenderer.setProperties(style); newRenderer.setRenderers(JavaBeanUtil.clone(renderers)); final String name = getName(); if (name.equals("Filter Style")) { newRenderer.setName("Scale Style"); } else if (name.equals("Multiple Style")) { newRenderer.setName("Scale Style"); } replace(layer, parent, newRenderer); return newRenderer; } @Override @SuppressWarnings("unchecked") public <V extends LayerRenderer<?>> V getRenderer(final List<String> path) { LayerRenderer<?> renderer = this; final int pathSize = path.size(); for (int i = 0; i < pathSize; i++) { final String name = path.get(i); final String rendererName = renderer.getName(); if (DataType.equal(name, rendererName)) { if (i < pathSize - 1) { final String childName = path.get(i + 1); if (renderer instanceof AbstractMultipleRenderer) { final AbstractMultipleRenderer multipleRenderer = (AbstractMultipleRenderer)renderer; renderer = multipleRenderer.getRenderer(childName); } } } else { return null; } } return (V)renderer; } @SuppressWarnings("unchecked") public <V extends LayerRenderer<?>> V getRenderer(final String name) { if (Property.hasValue(name)) { for (final LayerRenderer<?> renderer : this.renderers) { final String rendererName = renderer.getName(); if (DataType.equal(name, rendererName)) { return (V)renderer; } } } return null; } public List<AbstractRecordLayerRenderer> getRenderers() { synchronized (this.renderers) { return new ArrayList<>(this.renderers); } } public boolean hasRendererWithSameName(final LayerRenderer<?> renderer, final String name) { for (final AbstractRecordLayerRenderer otherRenderer : this.renderers) { if (renderer != otherRenderer) { final String layerName = otherRenderer.getName(); if (name.equals(layerName)) { return true; } } } return false; } public boolean isEmpty() { return this.renderers.isEmpty(); } @Override public boolean isVisible(final LayerRecord record) { if (super.isVisible() && super.isVisible(record)) { for (final AbstractRecordLayerRenderer renderer : getRenderers()) { if (renderer.isVisible(record)) { return true; } } } return false; } @Override public void refreshIcon() { if (this.renderers != null) { for (final AbstractRecordLayerRenderer renderer : this.renderers) { renderer.refreshIcon(); } } } public int removeRenderer(final AbstractRecordLayerRenderer renderer) { boolean removed = false; synchronized (this.renderers) { final int index = this.renderers.indexOf(renderer); if (index != -1) { if (renderer.getParent() == this) { renderer.setParent(null); } removed = this.renderers.remove(renderer); } if (removed) { firePropertyChange("renderers", index, renderer, null); } return index; } } @Override public void setLayer(final AbstractRecordLayer layer) { super.setLayer(layer); refreshIcon(); } public void setRenderers(final List<? extends AbstractRecordLayerRenderer> renderers) { List<AbstractRecordLayerRenderer> oldValue; synchronized (this.renderers) { oldValue = Lists.toArray(this.renderers); for (final AbstractRecordLayerRenderer renderer : this.renderers) { renderer.setParent(null); } if (renderers == null) { this.renderers.clear(); } this.renderers = new ArrayList<>(renderers); for (final AbstractRecordLayerRenderer renderer : this.renderers) { renderer.setParent(this); } } firePropertyChange("renderers", oldValue, this.renderers); } public void setStyles(final List<?> styles) { if (Property.hasValue(styles)) { final List<AbstractRecordLayerRenderer> renderers = new ArrayList<>(); for (final Object childStyle : styles) { if (childStyle instanceof AbstractRecordLayerRenderer) { final AbstractRecordLayerRenderer renderer = (AbstractRecordLayerRenderer)childStyle; renderers.add(renderer); } else { Logs.error(this, "Cannot create renderer for: " + childStyle); } } setRenderers(renderers); } } @Override public MapEx toMap() { final MapEx map = super.toMap(); final List<AbstractRecordLayerRenderer> renderers = getRenderers(); if (!renderers.isEmpty()) { final List<Map<String, Object>> rendererMaps = new ArrayList<>(); for (final AbstractRecordLayerRenderer renderer : renderers) { rendererMaps.add(renderer.toMap()); } addToMap(map, "styles", rendererMaps); } return map; } }