Changeset 3848 in josm


Ignore:
Timestamp:
2011-02-02T23:03:00+01:00 (13 years ago)
Author:
bastiK
Message:

Experimental mapcss support. All *.java files in the gui/mappaint/mapcss/parser folder are generated from the javacc source file MapCSSParser.jj in the same folder. The generated code sums up to 2700 lines, there is no further build dependency.

Location:
trunk/src/org/openstreetmap/josm
Files:
18 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/Preferences.java

    r3840 r3848  
    3131import org.openstreetmap.josm.Main;
    3232import org.openstreetmap.josm.tools.ColorHelper;
     33import org.openstreetmap.josm.tools.Utils;
    3334
    3435/**
     
    668669
    669670    synchronized public boolean putCollection(String key, Collection<String> val) {
    670         return put(key, join("\u001e", val));
     671        return put(key, Utils.join("\u001e", val));
    671672    }
    672673
    673674    synchronized private void putCollectionDefault(String key, Collection<String> val) {
    674         putDefault(key, join("\u001e", val));
     675        putDefault(key, Utils.join("\u001e", val));
    675676    }
    676677
     
    767768        putCollection("pluginmanager.sites", sites);
    768769    }
    769 
    770     /**
    771      * Joins a collection of strings into a single string with fields
    772      * separated by the value of sep.
    773      * @param sep the separator
    774      * @param values collection of strings, null strings are converted to the
    775      *  empty string
    776      * @return null if values is null. The joined string otherwise.
    777      */
    778     public static String join(String sep, Collection<?> values) {
    779         if (values == null)
    780             return null;
    781         if (values.isEmpty())
    782             return "";
    783         StringBuilder s = null;
    784         for (Object a : values) {
    785             if (a == null) {
    786                 a = "";
    787             }
    788             if(s != null) {
    789                 s.append(sep).append(a.toString());
    790             } else {
    791                 s = new StringBuilder(a.toString());
    792             }
    793         }
    794         return s.toString();
    795     }
    796 
    797770}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDialog.java

    r3801 r3848  
    1010import java.util.List;
    1111
     12import javax.swing.event.ChangeEvent;
    1213import javax.swing.JPanel;
    1314import javax.swing.JScrollPane;
     15import javax.swing.JTabbedPane;
    1416import javax.swing.JTextArea;
     17import javax.swing.SingleSelectionModel;
     18import javax.swing.event.ChangeListener;
    1519
    1620import org.openstreetmap.josm.Main;
     
    2428import org.openstreetmap.josm.data.osm.User;
    2529import org.openstreetmap.josm.data.osm.Way;
     30import org.openstreetmap.josm.gui.DefaultNameFormatter;
     31import org.openstreetmap.josm.gui.NavigatableComponent;
     32import org.openstreetmap.josm.gui.mappaint.ElemStyle;
     33import org.openstreetmap.josm.gui.mappaint.ElemStyles;
     34import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
     35import org.openstreetmap.josm.gui.mappaint.MultiCascade;
     36import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
     37import org.openstreetmap.josm.gui.mappaint.StyleSource;
     38import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
     39import org.openstreetmap.josm.gui.mappaint.xml.XmlStyleSource;
    2640import org.openstreetmap.josm.tools.DateUtils;
    2741import org.openstreetmap.josm.tools.GBC;
     
    3852public class InspectPrimitiveDialog extends ExtendedDialog {
    3953    protected Collection<OsmPrimitive> primitives;
    40     protected JTextArea textArea;
     54    private JTextArea txtData;
     55    private JTextArea txtMappaint;
     56    boolean mappaintTabLoaded;
    4157
    4258    public InspectPrimitiveDialog(Collection<OsmPrimitive> primitives) {
    4359        super(Main.parent, tr("Advanced object info"), new String[] {"Close"});
    4460        this.primitives = primitives;
    45         setPreferredSize(new Dimension(450, 350));
     61        setPreferredSize(new Dimension(750, 550));
    4662
    4763        setButtonIcons(new String[] {"ok.png"});
    48         JPanel p = buildPanel();
    49         textArea.setText(buildText());
    50         setContent(p, false);
    51     }
    52 
    53     protected JPanel buildPanel() {
     64        final JTabbedPane tabs = new JTabbedPane();
     65        JPanel pData = buildDataPanel();
     66        tabs.addTab(tr("data"), pData);
     67        final JPanel pMapPaint = new JPanel();
     68        tabs.addTab(tr("map style"), pMapPaint);
     69        tabs.getModel().addChangeListener(new ChangeListener() {
     70
     71            @Override
     72            public void stateChanged(ChangeEvent e) {
     73                if (!mappaintTabLoaded && ((SingleSelectionModel) e.getSource()).getSelectedIndex() == 1) {
     74                    mappaintTabLoaded = true;
     75                    buildMapPaintPanel(pMapPaint);
     76                    createMapPaintText();
     77                }
     78            }
     79        });
     80        txtData.setText(buildDataText());
     81        setContent(tabs, false);
     82    }
     83
     84    protected JPanel buildDataPanel() {
    5485        JPanel p = new JPanel(new GridBagLayout());
    55         textArea = new JTextArea();
    56         textArea.setFont(new Font("Monospaced", textArea.getFont().getStyle(), textArea.getFont().getSize()));
    57         textArea.setEditable(false);
    58 
    59         JScrollPane scroll = new JScrollPane(textArea);
     86        txtData = new JTextArea();
     87        txtData.setFont(new Font("Monospaced", txtData.getFont().getStyle(), txtData.getFont().getSize()));
     88        txtData.setEditable(false);
     89
     90        JScrollPane scroll = new JScrollPane(txtData);
    6091
    6192        p.add(scroll, GBC.std().fill());
     
    6394    }
    6495
    65     protected String buildText() {
     96    protected String buildDataText() {
    6697        StringBuilder s = new StringBuilder();
    6798        for (Node n : new SubclassFilteredCollection<OsmPrimitive, Node>(primitives, OsmPrimitive.nodePredicate)) {
     
    229260        return us.toString();
    230261    }
     262
     263    protected void buildMapPaintPanel(JPanel p) {
     264        p.setLayout(new GridBagLayout());
     265        txtMappaint = new JTextArea();
     266        txtMappaint.setFont(new Font("Monospaced", txtMappaint.getFont().getStyle(), txtMappaint.getFont().getSize()));
     267        txtMappaint.setEditable(false);
     268
     269        p.add(new JScrollPane(txtMappaint), GBC.std().fill());
     270    }
     271
     272    protected void createMapPaintText() {
     273        final Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
     274        ElemStyles elemstyles = MapPaintStyles.getStyles();
     275        NavigatableComponent nc = Main.map.mapView;
     276        double scale = nc.getDist100Pixel();
     277
     278        for (OsmPrimitive osm : sel) {
     279            txtMappaint.append("Styles Cache for \""+osm.getDisplayName(DefaultNameFormatter.getInstance())+"\":");
     280
     281            MultiCascade mc = new MultiCascade();
     282
     283            for (StyleSource s : elemstyles.getStyleSources()) {
     284                if (s.active) {
     285                    txtMappaint.append("\n\n> applying "+getSort(s)+" style \""+s.getDisplayString()+"\n");
     286                    s.apply(mc, osm, scale, null, false);
     287                    txtMappaint.append("\nRange:"+mc.range);
     288                    for (String key : mc.keySet()) {
     289                        txtMappaint.append("\n "+key+": \n"+mc.get(key));
     290                    }
     291                } else {
     292                    txtMappaint.append("\n\n> skipping \""+s.getDisplayString()+"\" (not active)");
     293                }
     294            }
     295            txtMappaint.append("\n\nList of generated Styles:\n");
     296            StyleList sl = elemstyles.get(osm, scale, nc);
     297            for (ElemStyle s : sl) {
     298                txtMappaint.append(" * "+s+"\n");
     299            }
     300            txtMappaint.append("\n\n");
     301        }
     302    }
     303
     304    private String getSort(StyleSource s) {
     305        if (s instanceof XmlStyleSource)
     306            return "xml";
     307        if (s instanceof MapCSSStyleSource)
     308            return "mapcss";
     309        return "unkown";
     310    }
     311
    231312}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java

    r3843 r3848  
    77import java.awt.Dimension;
    88import java.awt.Point;
    9 import java.awt.Rectangle;
    109import java.awt.event.ActionEvent;
    1110import java.awt.event.KeyEvent;
     
    2221import javax.swing.JTable;
    2322import javax.swing.ListSelectionModel;
     23import javax.swing.SwingUtilities;
    2424import javax.swing.UIManager;
    2525import javax.swing.event.ListSelectionEvent;
     
    2929import org.openstreetmap.josm.Main;
    3030import org.openstreetmap.josm.gui.SideButton;
    31 import org.openstreetmap.josm.gui.mappaint.ElemStyles;
    3231import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
     32import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.MapPaintStyleLoader;
    3333import org.openstreetmap.josm.gui.mappaint.StyleSource;
    3434import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
     
    151151                model.fireTableDataChanged();
    152152            }
    153             ElemStyles.cacheIdx++;
     153            MapPaintStyles.getStyles().clearCached();
    154154            Main.map.mapView.preferenceChanged(null);
    155155            Main.map.mapView.repaint();
     
    207207        @Override
    208208        public void actionPerformed(ActionEvent e) {
    209             int[] pos = tblStyles.getSelectedRows();
    210             for (int p : pos) {
    211                 StyleSource s = model.data.get(p);
    212                 s.loadStyleSource();
    213             }
    214             ElemStyles.cacheIdx++;
    215             Main.map.mapView.preferenceChanged(null);
    216             Main.map.mapView.repaint();
    217         }
    218     }
    219 
     209
     210            final int[] rows = tblStyles.getSelectedRows();
     211            List<StyleSource> sources = new ArrayList<StyleSource>();
     212            for (int p : rows) {
     213                sources.add(model.data.get(p));
     214            }
     215            Main.worker.submit(new MapPaintStyleLoader(sources));
     216            Main.worker.submit(new Runnable() {
     217                @Override
     218                public void run() {
     219                    SwingUtilities.invokeLater(new Runnable() {
     220                        @Override
     221                        public void run() {
     222                            if (rows.length == 1) {
     223                                model.fireTableCellUpdated(rows[0], 1);
     224                            } else {
     225                                model.fireTableDataChanged();
     226                            }
     227                            MapPaintStyles.getStyles().clearCached();
     228                            Main.map.mapView.preferenceChanged(null);
     229                            Main.map.mapView.repaint();
     230                        }
     231                    });
     232                }
     233            });
     234        }
     235    }
     236   
    220237    class PopupMenuHandler extends PopupMenuLauncher {
    221238        @Override
  • trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java

    r3836 r3848  
    2121
    2222    public static AreaElemStyle create(Cascade c) {
    23         Color color = c.get("fill-color", null, Color.class);
     23        Color color = c.getColor("fill-color", null);
    2424        if (color == null)
    2525            return null;
  • trunk/src/org/openstreetmap/josm/gui/mappaint/Cascade.java

    r3836 r3848  
    22package org.openstreetmap.josm.gui.mappaint;
    33
     4import java.awt.Color;
     5import java.util.Arrays;
    46import java.util.HashMap;
    57import java.util.Map;
     8
     9import org.openstreetmap.josm.gui.mappaint.mapcss.CSSColors;
    610
    711/**
    812 * Simple map of properties with dynamic typing.
    913 */
    10 public class Cascade {
     14public class Cascade implements Cloneable {
    1115   
    1216    public static final Cascade EMPTY_CASCADE = new Cascade();
     
    3236            return res;
    3337        }
    34         System.err.println(String.format("Warning: wrong type for mappaint property %s: %s expected, but %s found!", key, klass, o.getClass()));
     38        System.err.println(String.format("Warning: wrong type for mappaint property %s: %s expected, but %s of type %s found!", key, klass, o, o.getClass()));
     39        return def;
     40    }
     41
     42    public Object get(String key) {
     43        return prop.get(key);
     44    }
     45
     46    public Float getFloat(String key, Float def) {
     47        Object o = prop.get(key);
     48        if (o == null)
     49            return def;
     50        if (o instanceof Float)
     51            return (Float) o;
     52        if (o instanceof Integer)
     53            return new Float((Integer) o);
     54        return def;
     55    }
     56
     57    public Color getColor(String key, Color def) {
     58        Object o = prop.get(key);
     59        if (o == null)
     60            return def;
     61        if (o instanceof Color)
     62            return (Color) o;
     63        if (o instanceof String) {
     64            Color clr = CSSColors.get((String) o);
     65            if (clr != null)
     66                return clr;
     67            else
     68                return def;
     69        }
    3570        return def;
    3671    }
     
    5186        prop.remove(key);
    5287    }
     88
     89    @Override
     90    public Cascade clone() {
     91        @SuppressWarnings("unchecked")
     92        HashMap<String, Object> clonedProp = (HashMap) ((HashMap) this.prop).clone();
     93        Cascade c = new Cascade();
     94        c.prop = clonedProp;
     95        return c;
     96    }
     97
     98    @Override
     99    public String toString() {
     100        StringBuilder res = new StringBuilder("Cascade{ ");
     101        for (String key : prop.keySet()) {
     102            res.append(key+":");
     103            Object val = prop.get(key);
     104            if (val instanceof float[]) {
     105                res.append(Arrays.toString((float[]) val));
     106            } else {
     107                res.append(val+"");
     108            }
     109            res.append("; ");
     110        }
     111        return res.append("}").toString();
     112    }
    53113}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java

    r3836 r3848  
    1717
    1818    protected ElemStyle(Cascade c) {
    19         z_index = c.get("z-index", 0f, Float.class);
    20         object_z_index = c.get("object-z-index", 0f, Float.class);
     19        z_index = c.getFloat("z-index", 0f);
     20        object_z_index = c.getFloat("object-z-index", 0f);
    2121    }
    2222
  • trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java

    r3844 r3848  
    2828    private boolean drawMultipolygon;
    2929
    30     public static int cacheIdx;
     30    private int cacheIdx;
    3131
    3232    public ElemStyles()
    3333    {
    3434        styleSources = new ArrayList<StyleSource>();
     35    }
     36
     37    public void clearCached() {
     38        cacheIdx++;
    3539    }
    3640
  • trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java

    r3836 r3848  
    4040
    4141    public static LineElemStyle createCasing(Cascade c) {
    42         return createImpl(c, "casing-");
     42        LineElemStyle casing =  createImpl(c, "casing-");
     43        if (casing != null) {
     44            casing.object_z_index = -1;
     45        }
     46        return casing;
    4347    }
    4448
    4549    private static LineElemStyle createImpl(Cascade c, String prefix) {
    46         Float width = c.get(prefix + "width", null, Float.class);
     50        Float width = c.getFloat(prefix + "width", null);
    4751        if (width == null)
    4852            return null;
    4953
    50         float realWidth = c.get(prefix + "real-width", 0f, Float.class);
    51         Color color = c.get(prefix + "color", null, Color.class);
     54        float realWidth = c.getFloat(prefix + "real-width", 0f);
     55        Color color = c.getColor(prefix + "color", null);
    5256        if (color == null) {
    53             color = c.get(prefix + "fill-color", null, Color.class);
     57            color = c.getColor(prefix + "fill-color", null);
    5458        }
    5559        if (color == null) {
    56             color = PaintColors.UNTAGGED_WAY.get();
     60            color = PaintColors.UNTAGGED.get();
    5761        }
    5862        float[] dashes = c.get(prefix + "dashes", null, float[].class);
    59         Color dashesBackground = c.get(prefix + "dashes-background-color", null, Color.class);
     63        Color dashesBackground = c.getColor(prefix + "dashes-background-color", null);
    6064
    6165        return new LineElemStyle(c, width, realWidth, color, dashes, dashesBackground);
  • trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java

    r3843 r3848  
    1414
    1515import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.gui.PleaseWaitRunnable;
     17import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
    1618import org.openstreetmap.josm.gui.mappaint.xml.XmlStyleSource;
    1719import org.openstreetmap.josm.gui.preferences.SourceEntry;
    1820import org.openstreetmap.josm.gui.preferences.MapPaintPreference.MapPaintPrefMigration;
     21import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    1922import org.openstreetmap.josm.io.MirroredInputStream;
    2023import org.openstreetmap.josm.tools.ImageProvider;
     
    8386
    8487        for (SourceEntry entry : sourceEntries) {
    85             StyleSource style = new XmlStyleSource(entry);
     88            StyleSource style = null;
    8689            try {
    8790                MirroredInputStream in = new MirroredInputStream(entry.url);
    8891                InputStream zip = in.getZipEntry("xml","style");
    8992                if (zip != null) {
    90                     style.zipIcons = in.getFile();
    91                 }
     93                    style = new XmlStyleSource(entry);
     94                    continue;
     95                }
     96                zip = in.getZipEntry("mapcss","style");
     97                if (zip != null) {
     98                    style = new MapCSSStyleSource(entry);
     99                    continue;
     100                }
     101                if (entry.url.toLowerCase().endsWith(".mapcss")) {
     102                    style = new MapCSSStyleSource(entry);
     103                } else {
     104                    style = new XmlStyleSource(entry);
     105                }
    92106            } catch(IOException e) {
    93107                System.err.println(tr("Warning: failed to load Mappaint styles from ''{0}''. Exception was: {1}", entry.url, e.toString()));
    94108                e.printStackTrace();
    95                 style.hasError = true;
     109                if (style != null) {
     110                    style.hasError = true;
     111                }
    96112            }
    97             styles.add(style);
     113            if (style != null) {
     114                styles.add(style);
     115            }
    98116        }
    99117        for (StyleSource s : styles.getStyleSources()) {
     
    101119        }
    102120    }
     121
     122    public static class MapPaintStyleLoader extends PleaseWaitRunnable {
     123        private boolean canceled;
     124        private List<StyleSource> sources;
     125
     126        public MapPaintStyleLoader(List<StyleSource> sources) {
     127            super(tr("Reloading style sources"));
     128            this.sources = sources;
     129        }
     130
     131        @Override
     132        protected void cancel() {
     133            canceled = true;
     134        }
     135
     136        @Override
     137        protected void finish() {
     138        }
     139
     140        @Override
     141        protected void realRun() {
     142            ProgressMonitor monitor = getProgressMonitor();
     143            monitor.setTicksCount(sources.size());
     144            for (StyleSource s : sources) {
     145                if (canceled)
     146                    return;
     147                monitor.subTask(tr("loading style ''{0}''...", s.getDisplayString()));
     148                s.loadStyleSource();
     149                monitor.worked(1);
     150            }
     151        }
     152    }
     153
    103154}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSource.java

    r3844 r3848  
    3232public class XmlStyleSource extends StyleSource {
    3333
    34     public final HashMap<String, IconPrototype> icons = new HashMap<String, IconPrototype>();
    35     public final HashMap<String, LinePrototype> lines = new HashMap<String, LinePrototype>();
    36     public final HashMap<String, LinemodPrototype> modifiers = new HashMap<String, LinemodPrototype>();
    37     public final HashMap<String, AreaPrototype> areas = new HashMap<String, AreaPrototype>();
    38     public final LinkedList<IconPrototype> iconsList = new LinkedList<IconPrototype>();
    39     public final LinkedList<LinePrototype> linesList = new LinkedList<LinePrototype>();
    40     public final LinkedList<LinemodPrototype> modifiersList = new LinkedList<LinemodPrototype>();
    41     public final LinkedList<AreaPrototype> areasList = new LinkedList<AreaPrototype>();
     34    protected final HashMap<String, IconPrototype> icons = new HashMap<String, IconPrototype>();
     35    protected final HashMap<String, LinePrototype> lines = new HashMap<String, LinePrototype>();
     36    protected final HashMap<String, LinemodPrototype> modifiers = new HashMap<String, LinemodPrototype>();
     37    protected final HashMap<String, AreaPrototype> areas = new HashMap<String, AreaPrototype>();
     38    protected final LinkedList<IconPrototype> iconsList = new LinkedList<IconPrototype>();
     39    protected final LinkedList<LinePrototype> linesList = new LinkedList<LinePrototype>();
     40    protected final LinkedList<LinemodPrototype> modifiersList = new LinkedList<LinemodPrototype>();
     41    protected final LinkedList<AreaPrototype> areasList = new LinkedList<AreaPrototype>();
    4242
    4343    public XmlStyleSource(String url, String name, String shortdescription) {
     
    4949    }
    5050
     51    protected void init() {
     52        icons.clear();
     53        lines.clear();
     54        modifiers.clear();
     55        areas.clear();
     56        iconsList.clear();
     57        linesList.clear();
     58        modifiersList.clear();
     59        areasList.clear();
     60    }
     61
    5162    @Override
    5263    public void loadStyleSource() {
     64        init();
    5365        try {
    5466            MirroredInputStream in = new MirroredInputStream(url);
     
    5769            if (zip != null) {
    5870                reader = new InputStreamReader(zip);
     71                zipIcons = in.getFile();
    5972            } else {
    6073                reader = new InputStreamReader(in);
     74                zipIcons = null;
    6175            }
    6276
     
    288302                def.putOrClear("dashes-background-color", p.line.dashedColor);
    289303            }
    290             Float refWidth = def.get("width", null, Float.class);
     304            Float refWidth = def.getFloat("width", null);
    291305            if (refWidth != null && p.linemods != null) {
    292306                int numOver = 0, numUnder = 0;
  • trunk/src/org/openstreetmap/josm/gui/preferences/MapPaintPreference.java

    r3797 r3848  
    2121
    2222import org.openstreetmap.josm.Main;
    23 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    24 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2523import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    2624import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
     
    3028    private SourceEditor sources;
    3129    private JCheckBox enableIconDefault;
    32     private JCheckBox enableDefault;
    3330    private JComboBox styleCombo = new JComboBox();
    3431
     
    4037
    4138    public void addGui(final PreferenceTabbedPane gui) {
    42         enableDefault = new JCheckBox(tr("Enable built-in defaults"),
    43                 Main.pref.getBoolean("mappaint.style.enable-defaults", true));
    4439        enableIconDefault = new JCheckBox(tr("Enable built-in icon defaults"),
    4540                Main.pref.getBoolean("mappaint.icon.enable-defaults", true));
     
    168163
    169164    public boolean ok() {
    170         Boolean restart = Main.pref.put("mappaint.style.enable-defaults", enableDefault.isSelected());
     165        Boolean restart = false;
    171166        if(Main.pref.put("mappaint.icon.enable-defaults", enableIconDefault.isSelected())) {
    172167            restart = true;
     
    178173        && Main.isDisplayingMapView())
    179174        {
    180           for(OsmDataLayer l : Main.map.mapView.getLayersOfType(OsmDataLayer.class))
    181           {
    182             for(OsmPrimitive osm : l.data.allPrimitives())
    183             {
    184               osm.clearCached();
    185             }
    186           }
     175            MapPaintStyles.getStyles().clearCached();
    187176        }
    188177        return restart;
  • trunk/src/org/openstreetmap/josm/tools/Utils.java

    r3836 r3848  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.tools;
     3
     4import java.util.Collection;
    35
    46public class Utils {
     
    8082    }
    8183
     84    /**
     85     * Joins a list of strings (or objects that can be converted to string via
     86     * Object.toString()) into a single string with fields separated by sep.
     87     * @param sep the separator
     88     * @param values collection of objects, null is converted to the
     89     *  empty string
     90     * @return null if values is null. The joined string otherwise.
     91     */
     92    public static String join(String sep, Collection<?> values) {
     93        if (sep == null)
     94            throw new IllegalArgumentException();
     95        if (values == null)
     96            return null;
     97        if (values.isEmpty())
     98            return "";
     99        StringBuilder s = null;
     100        for (Object a : values) {
     101            if (a == null) {
     102                a = "";
     103            }
     104            if(s != null) {
     105                s.append(sep).append(a.toString());
     106            } else {
     107                s = new StringBuilder(a.toString());
     108            }
     109        }
     110        return s.toString();
     111    }
    82112}
Note: See TracChangeset for help on using the changeset viewer.