/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2007 - 2008, Open Source Geospatial Foundation (OSGeo) * (C) 2008 - 2009, Johann Sorel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.gui.swing.style; import java.awt.Component; import java.awt.Dimension; import java.awt.LayoutManager; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.ServiceLoader; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; import javax.swing.JPanel; import org.geotoolkit.factory.FactoryFinder; import org.geotoolkit.factory.Hints; import org.geotoolkit.gui.swing.util.JOptionDialog; import org.geotoolkit.map.MapLayer; import org.geotoolkit.style.MutableStyleFactory; import org.apache.sis.util.logging.Logging; import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.Expression; import org.opengis.style.Description; import org.opengis.style.Symbolizer; import org.opengis.util.InternationalString; /** * Style element editor * * @param <T> : style element class edited * @author Johann Sorel * @module */ public abstract class StyleElementEditor<T> extends JPanel { /** * Called when the style definition has changed. */ public static final String PROPERTY_UPDATED = "updated"; /** * The service loader. This loader and its iterator are not synchronized; * when doing an iteration, the iterator must be used inside synchronized blocks. */ private static final ServiceLoader<StyleElementEditor> LOADER = ServiceLoader.load(StyleElementEditor.class); protected static final Logger LOGGER = Logging.getLogger("org.geotoolkit.gui.swing.style"); private static MutableStyleFactory STYLE_FACTORY = null; private static FilterFactory2 FILTER_FACTORY = null; private final Class<T> targetClass; public StyleElementEditor(Class<T> targetClass){ this.targetClass = targetClass; } public StyleElementEditor(LayoutManager layout, Class<T> targetClass){ super(layout); this.targetClass = targetClass; } /** * * @param candidate * @return true if the given object can be edited by this editor. */ public boolean canHandle(Object candidate){ return targetClass.isInstance(candidate); } /** * @return supported edited class. */ public Class<T> getEditedClass() { return targetClass; } /** * Style element nearly always have an Expression field * the layer is used to fill the possible attribut in the expression editor * @param layer */ public void setLayer(final MapLayer layer){} /** * Layer used for expression edition in the style element * @return MapLayer */ public MapLayer getLayer(){ return null; } /** * the the edited object * @param target : object to edit */ public abstract void parse(T target); /** * return the edited object if there is one. * Id no edited object has been set this will create a new one. * @return T object */ public abstract T create(); /** * Style editor elements are often group on a single panel. * Since each editor has it's own layout we need a way to align all the * first column components. This method is expected to return the largest * width of those components. * If there are none, value -1 should be return. * @return largest first column width */ public final int getLabelColumnWidth(){ int width = -1; for(Object obj : getFirstColumnComponents()){ if(obj instanceof StyleElementEditor){ width = Math.max(width, ((StyleElementEditor)obj).getLabelColumnWidth()); }else if(obj instanceof Component){ width = Math.max(width, ((Component)obj).getPreferredSize().width); } } return width; } /** * Set label column widgets width. * @param width */ public void setLabelColumnWidth(int width){ for(Object obj : getFirstColumnComponents()){ if(obj instanceof StyleElementEditor){ ((StyleElementEditor)obj).setLabelColumnWidth(width); }else if(obj instanceof Component){ final Dimension dim = ((Component)obj).getPreferredSize(); dim.width = width; ((Component)obj).setMinimumSize(new Dimension(dim)); ((Component)obj).setMaximumSize(new Dimension(dim)); ((Component)obj).setPreferredSize(new Dimension(dim)); ((Component)obj).revalidate(); ((Component)obj).repaint(); } } revalidate(); repaint(); } /** * List the first column components or sub style element editors. * @return never null, but can be empty */ protected abstract Object[] getFirstColumnComponents(); protected Expression getSymbolizerGeometryExpression(Symbolizer symbolizer){ return symbolizer.getGeometry(); } public static void alignLabelColumnWidth(StyleElementEditor ... editors){ int width = -1; for(StyleElementEditor obj : editors){ width = Math.max(width, obj.getLabelColumnWidth()); } if(width!=-1){ for(StyleElementEditor obj : editors){ obj.setLabelColumnWidth(width); } } } public void apply(){ } protected static synchronized MutableStyleFactory getStyleFactory(){ if(STYLE_FACTORY == null){ final Hints hints = new Hints(); hints.put(Hints.STYLE_FACTORY, MutableStyleFactory.class); STYLE_FACTORY = (MutableStyleFactory)FactoryFinder.getStyleFactory(hints); } return STYLE_FACTORY; } protected static synchronized FilterFactory2 getFilterFactory(){ if(FILTER_FACTORY == null){ final Hints hints = new Hints(); hints.put(Hints.FILTER_FACTORY, FilterFactory2.class); FILTER_FACTORY = (FilterFactory2) FactoryFinder.getFilterFactory(hints); } return FILTER_FACTORY; } /** * Will popup a small dialog with this style editor. */ public T show(Component parent, final MapLayer layer, final T target){ setLayer(layer); parse(target); int res = JOptionDialog.show(parent, this, JOptionPane.OK_CANCEL_OPTION); if(res == JOptionPane.OK_OPTION){ return create(); }else{ return null; } } protected static String descriptionTitleText(final Description desc){ if(desc == null){ return ""; }else{ final InternationalString str = desc.getTitle(); if(str != null){ return str.toString(); }else{ return ""; } } } protected static String descriptionAbstractText(final Description desc){ if(desc == null){ return ""; }else{ final InternationalString str = desc.getAbstract(); if(str != null){ return str.toString(); }else{ return ""; } } } /** * Search the registered StyleElementEditor for one which support the given * object. * * @param candidate * @return StyleElementEditor or null if no editor found */ public static synchronized StyleElementEditor findEditor(Object candidate) { for(StyleElementEditor editor : LOADER){ if(editor.canHandle(candidate)){ try { return editor.getClass().newInstance(); } catch (InstantiationException ex) { LOGGER.log(Level.WARNING, ex.getMessage(), ex); } catch (IllegalAccessException ex) { LOGGER.log(Level.WARNING, ex.getMessage(), ex); } } } return null; } /** * Find all editors which handle a class child of the given one. * * @param candidate * @return Collection<StyleElementEditor> , never null, but can be empty. * List is sorted by edited class name. */ public static synchronized List<StyleElementEditor> findEditorsForType(Class candidate){ final List<StyleElementEditor> editors = new ArrayList<StyleElementEditor>(); for(StyleElementEditor editor : LOADER){ if(candidate == null || candidate.isAssignableFrom(editor.getEditedClass())){ editors.add(editor); } } Collections.sort(editors, new Comparator<StyleElementEditor>(){ @Override public int compare(StyleElementEditor o1, StyleElementEditor o2) { return o1.getEditedClass().getSimpleName().compareTo(o2.getEditedClass().getSimpleName()); } }); return editors; } }