/******************************************************************************* * Copyright (c) 2010 Stefan A. Tzeggai. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v2.1 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Stefan A. Tzeggai - initial API and implementation ******************************************************************************/ package org.geopublishing.atlasStyler; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.Reader; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Locale; import java.util.Set; import java.util.TreeSet; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; import org.apache.log4j.Logger; import org.geopublishing.atlasStyler.AtlasStyler.LANGUAGE_MODE; import org.geopublishing.atlasStyler.rulesLists.SingleLineSymbolRuleList; import org.geopublishing.atlasStyler.rulesLists.SinglePointSymbolRuleList; import org.geopublishing.atlasStyler.rulesLists.SinglePolygonSymbolRuleList; import org.geopublishing.atlasStyler.rulesLists.SingleRuleList; import org.geotools.brewer.color.BrewerPalette; import org.geotools.brewer.color.ColorBrewer; import org.geotools.brewer.color.PaletteType; import org.geotools.styling.FeatureTypeStyle; import org.geotools.styling.Fill; import org.geotools.styling.Graphic; import org.geotools.styling.LineSymbolizer; import org.geotools.styling.Mark; import org.geotools.styling.PointSymbolizer; import org.geotools.styling.PolygonSymbolizer; import org.geotools.styling.Rule; import org.geotools.styling.Stroke; import org.geotools.styling.Style; import org.geotools.styling.StyleBuilder; import org.geotools.styling.Symbolizer; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.feature.type.GeometryDescriptor; import org.opengis.filter.FilterFactory; import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Literal; import de.schmitzm.geotools.LegendIconFeatureRenderer; import de.schmitzm.geotools.feature.FeatureUtil; import de.schmitzm.geotools.feature.FeatureUtil.GeometryForm; import de.schmitzm.geotools.styling.StyledFeaturesInterface; import de.schmitzm.geotools.styling.StyledLayerInterface; import de.schmitzm.geotools.styling.StylingUtil; import de.schmitzm.geotools.styling.chartsymbols.ChartGraphic; import de.schmitzm.i18n.Translation; import de.schmitzm.lang.LangUtil; import de.schmitzm.lang.ResourceProvider; import de.schmitzm.swing.CancelButton; import de.schmitzm.swing.OkButton; import de.schmitzm.swing.SwingUtil; public class ASUtil { static Logger LOGGER = Logger.getLogger(ASUtil.class); /** * {@link ResourceProvider}, der die Lokalisation fuer GUI-Komponenten des * Package {@code skrueger.sld} zur Verfuegung stellt. Diese sind in * properties-Datein unter {@code skrueger.sld} hinterlegt. */ private final static ResourceProvider RESOURCE = ResourceProvider .newInstance("locales.AtlasStylerTranslation", Locale.ENGLISH); private static BrewerPalette arthursPalette; /** * A flag that allows only one of these dialogs to pop up. */ static boolean askForStringOpen = false; static String askForStringResult; public static DecimalFormat df = new DecimalFormat("##0.000"); private static TableCellRenderer doubleTableCellRenderer; public static final FilterFactory ff = FeatureUtil.FILTER_FACTORY; public static final FilterFactory2 ff2 = FeatureUtil.FILTER_FACTORY2; public static final FileNameExtensionFilter FILTER_SLD = new FileNameExtensionFilter( "SLD", "sld", "xml", "SLD", "XML"); public static final FileNameExtensionFilter FILTER_SVG = new FileNameExtensionFilter( "SVG", "svg", "SVG"); public static final FileNameExtensionFilter FILTER_PNG = new FileNameExtensionFilter( "PNG", "png", "PNG"); public static final FileNameExtensionFilter FILTER_EXTERNALGRAPHIC_FORMATS = new FileNameExtensionFilter( "SVG/PNG", "svg", "SVG", "png", "PNG"); public static final FileNameExtensionFilter FILTER_GML = new FileNameExtensionFilter( "GML", "gml", "GML"); public static final FileNameExtensionFilter FILTER_ALLSUPPORTED = new FileNameExtensionFilter( ASUtil.R("Filetype_AllSupported"), "shp", "SHP", "zip", "ZIP", "gml", "GML", "tif", "TIF", "tiff", "TIFF", "a00", "asc", "ASC", "txt", "ascii", "ASCII"); public static final FileNameExtensionFilter FILTER_RASTERSUPPORTED = new FileNameExtensionFilter( ASUtil.R("Filetype_ImportableRaster"), "tif", "TIF", "tiff", "TIFF", "a00", "asc", "ASC", "txt"); public static final FileNameExtensionFilter FILTER_SHAPE = new FileNameExtensionFilter( ASUtil.R("Filetype_ShapeOrShapeAsZip"), "shp", "SHP", "zip", "ZIP"); public static final StyleBuilder SB = StylingUtil.STYLE_BUILDER; public static final String PRODUCTION_FILENAME_PART = "production"; /** * Asks to edit a {@link String} in a modal dialog. As we are working with * that stupid static {@link String}, we only allow one open {@link JDialog} * * @param preset * Optional the {@link String} to start editing with * * @return <code>null</code> is canceled. Otherwise the new {@link String} * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public static String askForString(final Component owner, final String preset, final String question) { // As we are working with that stupid static String, we only allow one // open Dialog if (askForStringOpen) return preset; askForStringOpen = true; final JTextField tf = new JTextField(20); final JDialog dialog = new JDialog(SwingUtil.getParentWindow(owner)) { private static final long serialVersionUID = 6629175844460277695L; /** * Since the registerKeyboardAction() method is part of the * JComponent class definition, you must define the Escape keystroke * and register the keyboard action with a JComponent, not with a * JDialog. The JRootPane for the JDialog serves as an excellent * choice to associate the registration, as this will always be * visible. If you override the protected createRootPane() method of * JDialog, you can return your custom JRootPane with the keystroke * enabled: */ @Override protected JRootPane createRootPane() { final KeyStroke stroke = KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0); final JRootPane rootPane = new JRootPane(); rootPane.registerKeyboardAction(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { askForStringResult = null; dispose(); } }, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW); final KeyStroke strokeEnter = KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, 0); rootPane.registerKeyboardAction(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { askForStringResult = tf.getText(); dispose(); } }, strokeEnter, JComponent.WHEN_IN_FOCUSED_WINDOW); return rootPane; } }; dialog.setLayout(new BorderLayout()); if (question != null) { dialog.setTitle(question); dialog.add(new JLabel(question + ":"), BorderLayout.WEST); } tf.setText(preset); dialog.add(tf, BorderLayout.CENTER); final JPanel buttons = new JPanel(); final OkButton okButton = new OkButton(); okButton.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { askForStringResult = tf.getText(); dialog.dispose(); } }); final CancelButton cancelButton = new CancelButton(); cancelButton.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { askForStringResult = null; dialog.dispose(); } }); buttons.add(okButton); buttons.add(cancelButton); dialog.add(buttons, BorderLayout.SOUTH); dialog.setModal(true); dialog.pack(); SwingUtil.setRelativeFramePosition(dialog, owner, 0.5, .5); dialog.setVisible(true); askForStringOpen = false; return askForStringResult; } public static Fill createDefaultFill() { return SB.createFill(); } public static Graphic createDefaultGraphic() { return SB.createGraphic(); } public static Graphic createDefaultGraphicFill() { return SB.createGraphic(); } /** * @return a default {@link Mark} with a <code>circle</code> * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public static final Mark createDefaultMark() { return SB.createMark("circle"); }; public static Stroke createDefaultStroke() { return SB.createStroke(); } /** * Creates a default Style that is compatible with {@link AtlasStylerVector} * . */ public static Style createDefaultStyle( final StyledLayerInterface<?> styledLayer) { final Style loadStyle = StylingUtil.createDefaultStyle(styledLayer); if (!(styledLayer instanceof StyledFeaturesInterface<?>)) { // Not compatible with AtlasStyler, but if it is no // StyledFeaturesInterface, we are not in AtlasStyler. TODO: Is this // a nice solution? return loadStyle; } // This method may not instantiate AtlasStyler with the styledLayer! It // would be recursive! StyledFeaturesInterface styledFs = (StyledFeaturesInterface) styledLayer; // final Style compatibleStyle = new // AtlasStyler((StyledFeaturesInterface<?>) styledLayer, // loadStyle, null, null).getStyle(); SingleRuleList<? extends Symbolizer> singleRulesList = new RuleListFactory( styledFs).createSingleRulesList( AtlasStylerVector.getRuleTitleFor(styledFs), true); Style defaultStyle = StylingUtil.STYLE_BUILDER.createStyle(); defaultStyle.featureTypeStyles().add(singleRulesList.getFTS()); return defaultStyle; } public static Symbolizer createDefaultSymbolizer( final GeometryDescriptor geomType) { switch (FeatureUtil.getGeometryForm(geomType)) { case POINT: return SB.createPointSymbolizer(); case LINE: return SB.createLineSymbolizer(); case POLYGON: return SB.createPolygonSymbolizer(); default: throw new RuntimeException("TYpe not recognized!"); } } /** * Creates a default {@link SimpleFeatureType} for a given class type * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public static SimpleFeatureType createFeatureType( final GeometryDescriptor defaultGeometry) { return FeatureUtil.createFeatureType(defaultGeometry.getType() .getBinding()); } private static BrewerPalette getArthursPalette() throws IOException { if (arthursPalette == null) { /** * Special hack for Arthur dunkelblau R:0 G:38 B:115 * * blau R: 0 G:0 B:255 * * hellblau R: 51 G: 194 B: 255 * * grün R: 182 G: 255 B:143 * * orange R: 255 G:200 B:0 * * rot R: 255 G:0 B:0 * * dunkel rot R: 168 G:0 B:0 */ arthursPalette = StylingUtil.createBrewerPalette("BlGrRe", new Color[] { new Color(0, 38, 115), new Color(0, 0, 255), new Color(51, 194, 225), new Color(182, 255, 143), new Color(255, 200, 0), new Color(255, 0, 0), new Color(168, 0, 0) }); for (int i = 2; i < 6; i++) { arthursPalette.getPaletteSuitability().setSuitability(i, new String[] { "?", "?", "?", "?", "?", "?" }); } arthursPalette.getColorScheme().setSampleScheme(2, new int[] { 1, 5 }); arthursPalette.getColorScheme().setSampleScheme(3, new int[] { 1, 3, 5 }); arthursPalette.getColorScheme().setSampleScheme(4, new int[] { 1, 2, 4, 5 }); arthursPalette.getColorScheme().setSampleScheme(5, new int[] { 1, 2, 3, 4, 5 }); arthursPalette.getColorScheme().setSampleScheme(6, new int[] { 0, 1, 2, 3, 4, 5 }); arthursPalette.getColorScheme().setSampleScheme(7, new int[] { 0, 1, 2, 3, 4, 5, 6 }); } return arthursPalette; } /** * Returns the index of the first (and hopefully only) attribute with that * LocalName. * * @param schema * The {@link SimpleFeatureType} to search * @param attName * Attribute name * @return -1 if not attribute with that name is found */ public static int getAttribIndex(final SimpleFeatureType schema, final String attName) { for (int position = 0; position < schema.getAttributeCount(); position++) { if (schema.getAttributeDescriptors().get(position).getLocalName() .equals(attName)) return position; } return -1; } /** * Returns the AttributeDescriptor of the first (and hopefully only) * attribute with that LocalName. * * @param schema * The {@link SimpleFeatureType} to search * @param attName * Attribute name * @return <code>null</code> if no attribute with that name is found */ public static AttributeDescriptor getAttribType( final SimpleFeatureType schema, final String attName) { for (int position = 0; position < schema.getAttributeCount(); position++) { if (schema.getAttributeDescriptors().get(position).getLocalName() .equals(attName)) return schema.getAttributeDescriptors().get(position); } return null; } public static Float getBiggestSize(final Fill fill, Float maxSize) { if (fill == null) return maxSize; maxSize = getBiggestSize(fill.getGraphicFill(), maxSize); return maxSize; } public static Float getBiggestSize(final Graphic graphic, Float maxSize) { if (graphic == null) return maxSize; final Expression size2 = graphic.getSize(); if (size2 != null && size2 != Expression.NIL) { try { final Float size = Float.valueOf(size2.toString()); if (size > maxSize) { maxSize = size; } } catch (final Exception e) { LOGGER.error("", e); } } // if (graphic.getMarks() != null) { // TODO Stefan Tzeggai 12.9.11 GT8 Migration // for (final Mark m : graphic.getMarks()) { // final Expression mSize = m.getSize(); // if (mSize != null && mSize != Expression.NIL) { // try { // final Float mSizeFloat = Float // .valueOf(mSize.toString()); // if (mSizeFloat > maxSize) { // maxSize = mSizeFloat; // } // } catch (final Exception e) { // LOGGER.error(e); // } // } // } // } // TODO external graphics sizes return maxSize; } public static Float getBiggestSize(final PointSymbolizer ps, Float maxSize) { maxSize = getBiggestSize(ps.getGraphic(), maxSize); return maxSize; } public static Float getBiggestSize(final PolygonSymbolizer ps, Float maxSize) { maxSize = getBiggestSize(ps.getFill(), maxSize); maxSize = getBiggestStrokeWidthOrGraphicSize(ps.getStroke(), maxSize); return maxSize; } public static Float getBiggestWidth(final LineSymbolizer ps, Float maxSize) { maxSize = getBiggestStrokeWidthOrGraphicSize(ps.getStroke(), maxSize); return maxSize; } public static Float getBiggestStrokeWidthOrGraphicSize(final Stroke stroke, Float maxSize) { if (stroke == null) return maxSize; if (stroke.getGraphicStroke() != null) { // If the Stroke uses a GrphicStroke, use it's size if (stroke.getGraphicStroke().getSize() != null && stroke.getGraphicStroke().getSize() != Expression.NIL) { final Float size = Float.valueOf(stroke.getGraphicStroke() .getSize().toString()); if (size > maxSize) { maxSize = size; } } } else { if (stroke.getWidth() != null && stroke.getWidth() != Expression.NIL) { final Float size = Float.valueOf(stroke.getWidth().toString()); if (size > maxSize) { maxSize = size; } } } return maxSize; } /** * http://www.velocityreviews.com/forums/t146956-popupmenu-for-a-cell-in-a- * jtable.html * * @param requestor * @return * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public static String getClipboardContents(final Object requestor) { final Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard() .getContents(requestor); if (t != null) { final DataFlavor df = DataFlavor.stringFlavor; if (df != null) { try { final Reader r = df.getReaderForText(t); final char[] charBuf = new char[512]; final StringBuffer buf = new StringBuffer(); int n; while ((n = r.read(charBuf, 0, charBuf.length)) > 0) { buf.append(charBuf, 0, n); } r.close(); return (buf.toString()); } catch (final IOException ex) { LOGGER.error(ex); } catch (final UnsupportedFlavorException ex) { LOGGER.error(ex); } } } return null; } /** * @return A default symbol to use for lines */ public static SingleLineSymbolRuleList getDefaultLineTemplate() { final SingleLineSymbolRuleList rl = new SingleLineSymbolRuleList(""); final LineSymbolizer symb = (LineSymbolizer) ASUtil .createDefaultSymbolizer(rl.getGeometryDescriptor()); rl.addSymbolizer(symb); return rl; } /** * Returns a default {@link SingleRuleList} symbol for NODATA values. If * {@link AtlasStylerVector} is running in multilanguage mode, it tries to * find a default legend label automatically for all languages. * * @param colors * none or one or two color paramters that will be used. */ public static SingleRuleList getDefaultNoDataSymbol( final GeometryForm form, final Color... colors) { return getDefaultNoDataSymbol(form, 1., colors); } /** * Returns a default {@link SingleRuleList} symbol for NODATA values. If * {@link AtlasStylerVector} is running in multilanguage mode, it tries to * find a default legend label automatically for all languages. * * @param colors * none or one or two color paramters that will be used. */ public static SingleRuleList<? extends Symbolizer> getDefaultNoDataSymbol( final GeometryForm form, final double opacity_fill, final Color... colors) { final SingleRuleList<? extends Symbolizer> rl; final Color defaultWhite = colors.length > 0 ? colors[0] : Color.WHITE; final Color defaultGray = colors.length > 1 ? colors[1] : Color.LIGHT_GRAY; switch (form) { case POINT: rl = new SinglePointSymbolRuleList(""); // A white circle is the default NODATA symbol for points rl.addSymbolizer(SB.createPointSymbolizer(SB.createGraphic(null, SB.createMark("circle", defaultWhite), null, opacity_fill, 8., 0.))); break; case POLYGON: rl = new SinglePolygonSymbolRuleList(""); // A 50% white fill is the default NODATA symbol for polygons rl.addSymbolizer(SB.createPolygonSymbolizer( SB.createStroke(defaultGray, 1, opacity_fill), SB.createFill(defaultWhite, opacity_fill))); break; default: case LINE: rl = new SingleLineSymbolRuleList(""); // A white line is the default NODATA symbol for lines rl.addSymbolizer(SB.createLineSymbolizer(defaultWhite)); break; } rl.setTitle("NODATA"); // Find suitable default labels if (AtlasStyler.languageMode == LANGUAGE_MODE.ATLAS_MULTILANGUAGE) { final Translation nodT = new Translation(); for (final String lang : AtlasStylerVector.getLanguages()) { // Try to find a default for every language final String localized = R(new Locale(lang), "NoDataLegendEntry.Default"); nodT.put(lang, localized); } rl.setRuleTitle(nodT); } else rl.setLabel(R("NoDataLegendEntry.Default")); return rl; } /** * @return A default symbol to use for points */ public static SinglePointSymbolRuleList getDefaultPointTemplate() { final SinglePointSymbolRuleList rl = new SinglePointSymbolRuleList(""); rl.addSymbolizer(createDefaultSymbolizer(rl.getGeometryDescriptor())); return rl; } public static SinglePolygonSymbolRuleList getDefaultPolygonTemplate() { final SinglePolygonSymbolRuleList rl = new SinglePolygonSymbolRuleList( ""); rl.addSymbolizer(createDefaultSymbolizer(rl.getGeometryDescriptor())); return rl; } public static SingleRuleList<? extends Symbolizer> getDefaultTemplate( final GeometryForm geomForm) { if (geomForm == GeometryForm.POINT) { return getDefaultPointTemplate(); } else if (geomForm == GeometryForm.LINE) { return getDefaultLineTemplate(); } else if (geomForm == GeometryForm.POLYGON) { return getDefaultPolygonTemplate(); } else throw new IllegalArgumentException(); } public static TableCellRenderer getDoubleCellRenderer() { if (doubleTableCellRenderer == null) doubleTableCellRenderer = new DefaultTableCellRenderer() { private static final long serialVersionUID = -7498350601156304636L; @Override public Component getTableCellRendererComponent( final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) { final JLabel label = (JLabel) super .getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); final NumberFormat doubleFormat = NumberFormat .getNumberInstance(); doubleFormat.setMinimumFractionDigits(3); doubleFormat.setMaximumFractionDigits(3); doubleFormat.setMinimumIntegerDigits(1); if (value instanceof Double) { final Double val = ((Double) value).doubleValue(); final String str = doubleFormat.format(val); label.setText(str); } // TODO monospaced font label.setHorizontalAlignment(SwingConstants.RIGHT); return label; } }; return doubleTableCellRenderer; } /** * @return an image using the AtlasStyler's default size */ public static BufferedImage getFillGraphicImage(final Graphic fillGraphic, final Color color, final Color backgroundColor, final SimpleFeatureType featuretype) { return getGraphicImage(fillGraphic, color, backgroundColor, 1., AtlasStylerVector.DEFAULT_SYMBOL_PREVIEW_SIZE, featuretype); } public static BufferedImage getFillImage(final Fill fill, final Dimension size, final SimpleFeatureType featureType) { final PolygonSymbolizer symb = SB.createPolygonSymbolizer(null, fill); return getSymbolizerImage(symb, size, featureType); } /** * @return an image using the AtlasStyler's default size */ public static BufferedImage getFillImage(final Fill fill, final SimpleFeatureType featureType) { return getFillImage(fill, AtlasStylerVector.DEFAULT_SYMBOL_PREVIEW_SIZE, featureType); } public static BufferedImage getGraphicImage(final Graphic graphic, final Color color, final Color backgroundColor, final double opacity, final Dimension size, final SimpleFeatureType featureType) { final Fill fill = SB.createFill(color, backgroundColor, opacity, graphic); return getFillImage(fill, size, featureType); } /** * When converting a {@link Number} (which is usually a {@link Double} * coming from the classification) to a literal, the SLD StreamingRenderer * need correct {@link Literal}s. This method returns a {@link Literal} that * fits the {@link AttributeDescriptor}s binding type. * * @param number * The number to express as a {@link Literal} * @return * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public static Literal getLiteralForField(final AttributeDescriptor at, final Number number) { final Class<?> c = at.getType().getBinding(); if (c == Long.class) { final long l1 = number.longValue(); return ff2.literal(l1); } else if (c == Byte.class) { final byte l1 = number.byteValue(); return ff2.literal(l1); } else if (c == Integer.class) { final int l1 = number.intValue(); return ff2.literal(l1); } else if (c == Short.class) { final int l1 = number.shortValue(); return ff2.literal(l1); } else { return ff2.literal(number); } } /** * Returns a list of {@link BrewerPalette} suitable for the given number of * classes. * * @param paletteTypeGraduation * @param numClasses * -1 may be passed. */ public static BrewerPalette[] getPalettes( final PaletteType paletteTypeGraduation, final int numClasses) { ColorBrewer brewer; try { brewer = ColorBrewer.instance(paletteTypeGraduation); } catch (final IOException e) { LOGGER.error("Error loading new PaletteType(true, false)", e); brewer = ColorBrewer.instance(); } BrewerPalette[] palettes = brewer.getPalettes(paletteTypeGraduation, numClasses); try { final BrewerPalette arthursPalette = getArthursPalette(); final int maxColors = arthursPalette.getMaxColors(); if (maxColors >= numClasses) palettes = LangUtil.extendArray(palettes, arthursPalette); } catch (final IOException e1) { LOGGER.error("Creating Arthurs special palette failed:", e1); } return palettes; } /** * Liefert eine Liste aller Sprachen, in die die {@link AtlasStylerGUI} * übersetzt ist. */ public static String[] getSupportedLanguages() { final Set<Locale> availableLocales = ResourceProvider .getAvailableLocales(RESOURCE, true); final ArrayList<String> list = new ArrayList<String>( availableLocales.size()); for (final Locale l : availableLocales) { list.add(l.getLanguage()); } return list.toArray(new String[0]); } public static BufferedImage getSymbolizerImage(Symbolizer symb, final Dimension size, final SimpleFeatureType featureType) { // TODO Caching? // Since this rule might well contain any ChartSymbols (which can not be // previewed without modification) we have to check all Symbolizers and // change any Chart-Symbolizers for proper preview. if (ChartGraphic.isChart(symb)) symb = ChartGraphic.getFixDataSymbolizer(symb); Rule rule = StylingUtil.STYLE_FACTORY.createRule(); rule.symbolizers().add(symb); final BufferedImage image = new LegendIconFeatureRenderer() .createImageForRule(rule, featureType, size); return image; } public static BufferedImage getSymbolizerImage(final Symbolizer symbolizer, final SimpleFeatureType featureType) { return getSymbolizerImage(symbolizer, AtlasStylerVector.DEFAULT_SYMBOL_PREVIEW_SIZE, featureType); } public static SingleLineSymbolRuleList importLineTemplateFromFirstRule( final FeatureTypeStyle fts) { SingleLineSymbolRuleList tempRL = new SingleLineSymbolRuleList( fts.getName()); try { final Rule rule0 = fts.rules().get(0); for (final Symbolizer ps : rule0.getSymbolizers()) { tempRL.addSymbolizer(ps); } tempRL.reverseSymbolizers(); } catch (final Exception e) { LOGGER.warn("Error " + e.getLocalizedMessage() + " while importing the template RL. Using default"); LOGGER.error(e); tempRL = getDefaultLineTemplate(); } return tempRL; } public static SinglePointSymbolRuleList importPointTemplateFromFirstRule( final FeatureTypeStyle importFTS) { SinglePointSymbolRuleList tempRL = new SinglePointSymbolRuleList( importFTS.getName()); try { final Rule rule0 = importFTS.rules().get(0); for (final Symbolizer ps : rule0.getSymbolizers()) { tempRL.addSymbolizer(ps); } tempRL.reverseSymbolizers(); } catch (final Exception e) { LOGGER.warn("Error " + e.getLocalizedMessage() + " while importing the template RL. Using default"); LOGGER.error(e); tempRL = getDefaultPointTemplate(); } return tempRL; } public static SinglePolygonSymbolRuleList importPolygonTemplateFromFirstRule( final FeatureTypeStyle importFTS) { SinglePolygonSymbolRuleList tempRL = new SinglePolygonSymbolRuleList( importFTS.getName()); try { final Rule rule0 = importFTS.rules().get(0); for (final Symbolizer ps : rule0.getSymbolizers()) { tempRL.addSymbolizer(ps); } tempRL.reverseSymbolizers(); } catch (final Exception e) { LOGGER.warn("Error " + e.getLocalizedMessage() + " while importing the template RL. Using default"); LOGGER.error(e); tempRL = getDefaultPolygonTemplate(); } return tempRL; } /** * http://www.velocityreviews.com/forums/t146956-popupmenu-for-a-cell-in-a- * jtable.html */ public static boolean isClipboardContainingText(final Object requestor) { final Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard() .getContents(requestor); return t != null && (t.isDataFlavorSupported(DataFlavor.stringFlavor) || t .isDataFlavorSupported(DataFlavor.plainTextFlavor)); } /** * Convenience method to access the {@link AtlasStylerVector}s translation * resources for a specific {@link Locale}. * * @param key * the key for the AtlasStylerTranslation.properties file * @param values * optional values */ public static String R(final Locale locale, final String key, final Object... values) { String string = RESOURCE.getString(key, locale, values); if (string.equals("???")) { string = "???" + key; LOGGER.error("missing key in AS: '" + key + "'"); } return string; } /** * Convenience method to access the {@link AtlasStylerVector}s translation * resources. * * @param key * the key for the AtlasStylerTranslation.properties file * @param values * optional values */ public static String R(final String key, final Object... values) { String string = RESOURCE.getString(key, values); if (string.equals("???")) { string = "???" + key; LOGGER.error("missing key in AS: '" + key + "'"); } return string; } public static void replaceFillSize(final Fill fill, final Float factor) { if (fill == null) return; replaceGraphicSize(fill.getGraphicFill(), factor); } public static void replaceGraphicSize(final Graphic graphic, final Float factor) { if (graphic == null) return; final Expression gSize = graphic.getSize(); if (gSize != null && gSize != Expression.NIL) { final Double newSize = Double.valueOf(gSize.toString()) * factor; // System.out.println("Changed a Graphics's size from to " // + Float.valueOf(graphic.getSize().toString()) + " to " // + newSize); graphic.setSize(ASUtil.ff2.literal(newSize)); } // else if (graphic.getMarks() != null) { // // TODO Stefan Tzeggai 12.9.11 GT8 Migration // for (final Mark m : graphic.getMarks()) { // final Expression mSize = m.getSize(); // if (mSize != null && mSize != Expression.NIL) { // final Float newSize = Float.valueOf(mSize.toString()) // * factor; // // System.out.println("Changed a Mark's size from to " // // + Double.valueOf(m.getSize().toString()) + " to " // // + newSize); // m.setSize(ASUtil.ff2.literal(newSize)); // } // } // } } /** * Replaces the "main" size in a given {@link PolygonSymbolizer} element */ public static void replacePolygonSymbolizerSize(final PolygonSymbolizer ps, final Float factor) { if (ps == null) return; replaceFillSize(ps.getFill(), factor); } /** * Rounds all elements of the {@link TreeSet} to the number of digits * specified by {@link #limitsDigits}. The first break (start of the first * interval) is rounded down and the last break (end of last interval) is * rounded up, so that every possible value is still included in one * interval. * * @param breaksList * interval breaks * @return a new {@link TreeSet} */ public static TreeSet<Double> roundLimits(final TreeSet<Double> breaksList, final Integer limitsDigits) { // No round -> use the original values if (limitsDigits == null) return breaksList; final TreeSet<Double> roundedBreaks = new TreeSet<Double>(); for (final double value : breaksList) { int roundMode = 0; // normal round // begin of first interval must be rounded DOWN, so that all // values are included if (value == breaksList.first()) roundMode = -1; // end of last interval must be rounded UP, so that all // values are included if (value == breaksList.last()) roundMode = 1; // round value and put it into the new TreeSet roundedBreaks.add(LangUtil.round(value, limitsDigits, roundMode)); } return roundedBreaks; } public static void selectOrInsert(final JComboBox comboBox, Double doubleVal) { // Round the value to the second decimal digit doubleVal = Math.floor(doubleVal * 100f) / 100f; final DefaultComboBoxModel model = ((DefaultComboBoxModel) comboBox .getModel()); final int indexOf = model.getIndexOf(doubleVal); if (indexOf < 0) { LOGGER.info("The Double expression " + doubleVal + " had to be inserted into the ComboBox"); final int size = model.getSize(); final Set<Double> doubles = new TreeSet<Double>(); doubles.add(doubleVal); for (int i = 0; i < size; i++) { final Double elementAt = (Double) model.getElementAt(i); if (elementAt != null) { doubles.add(elementAt); } else { LOGGER.warn("A null in the JComboBoxmodel has been ignored"); } } model.removeAllElements(); for (final Double f : doubles) { model.addElement(f); } } model.setSelectedItem(doubleVal); } public static void selectOrInsert(final JComboBox comboBox, final Expression expression) { if (expression instanceof Literal) { final Literal lit = (Literal) expression; if (comboBox.getItemAt(0) instanceof String) { final String stringVal = lit.toString(); selectOrInsert(comboBox, stringVal); } else if (comboBox.getItemAt(0) instanceof Double) { final Double doubleVal = Double.valueOf(lit.toString()); selectOrInsert(comboBox, doubleVal); } else if (comboBox.getItemAt(0) instanceof Float) { final Float floatVal = Float.valueOf(lit.toString()); selectOrInsert(comboBox, floatVal); } else { throw new RuntimeException("selectOrInsert neede for type " + comboBox.getItemAt(0)); } } } // // public static <ItemClass> void selectOrInsert(final JComboBox comboBox, // final ItemClass val) { // final DefaultComboBoxModel model = ((DefaultComboBoxModel) comboBox // .getModel()); // final int indexOf = model.getIndexOf(val); // // if (indexOf < 0) { // LOGGER.info("The float expression " + val // + " had to be inserted into the ComboBox"); // // final int size = model.getSize(); // final Set<ItemClass> ints = new TreeSet<ItemClass>(); // ints.add(val); // // for (int i = 0; i < size; i++) { // ints.add((ItemClass) model.getElementAt(i)); // } // model.removeAllElements(); // // for (final ItemClass f : ints) { // model.addElement(f); // } // } // model.setSelectedItem(val); // } // public static void selectOrInsert(final JComboBox comboBox, float floatVal) { // Round the value to the second decimal digit floatVal = (float) Math.floor(floatVal * 100f) / 100f; final DefaultComboBoxModel model = ((DefaultComboBoxModel) comboBox .getModel()); final int indexOf = model.getIndexOf(floatVal); if (indexOf < 0) { LOGGER.info("The float expression " + floatVal + " had to be inserted into the ComboBox"); final int size = model.getSize(); final Set<Float> floats = new TreeSet<Float>(); floats.add(floatVal); for (int i = 0; i < size; i++) { final Float elementAt = (Float) model.getElementAt(i); if (elementAt != null) { floats.add(elementAt); } else { LOGGER.warn("A null in the JComboBoxmodel has been ignored"); } } model.removeAllElements(); for (final Float f : floats) { model.addElement(f); } } model.setSelectedItem(floatVal); } public static void selectOrInsert(final JComboBox comboBox, Integer integerVal) { final DefaultComboBoxModel model = ((DefaultComboBoxModel) comboBox .getModel()); final int indexOf = model.getIndexOf(integerVal); if (indexOf < 0) { LOGGER.info("The integer expression " + integerVal + " had to be inserted into the ComboBox"); final int size = model.getSize(); final Set<Integer> integers = new TreeSet<Integer>(); integers.add(integerVal); for (int i = 0; i < size; i++) { final Integer elementAt = (Integer) model.getElementAt(i); if (elementAt != null) { integers.add(elementAt); } else { LOGGER.warn("A null in the JComboBoxmodel has been ignored"); } } model.removeAllElements(); for (final Integer f : integers) { model.addElement(f); } } model.setSelectedItem(integerVal); } public static void selectOrInsert(final JComboBox comboBox, final String stringVal) { final DefaultComboBoxModel model = ((DefaultComboBoxModel) comboBox .getModel()); final int indexOf = model.getIndexOf(stringVal); if (indexOf < 0) { LOGGER.info("The string expression " + stringVal + " had to be inserted into the ComboBox"); final int size = model.getSize(); final Set<String> strings = new TreeSet<String>(); strings.add(stringVal); for (int i = 0; i < size; i++) { final String elementAt = (String) model.getElementAt(i); if (elementAt != null) { strings.add(elementAt); } else { LOGGER.warn("A null in the JComboBoxmodel has been ignored"); } } model.removeAllElements(); for (final String f : strings) { model.addElement(f); } } model.setSelectedItem(stringVal); } /** * Changes the name of the original .sld file to the optimized version */ public static File changeToOptimizedFilename(File sldFile) { String pathname = sldFile.getAbsolutePath() .replaceAll("\\.sld", "." + PRODUCTION_FILENAME_PART + ".sld") .replaceAll("\\.SLD", "." + PRODUCTION_FILENAME_PART + ".SLD") .replaceAll("\\.xml", "." + PRODUCTION_FILENAME_PART + ".xml") .replaceAll("\\.XML", "." + PRODUCTION_FILENAME_PART + ".XML"); return new File(pathname); } }