/*
* 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.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import org.geotoolkit.display2d.GO2Utilities;
import org.geotoolkit.display2d.service.DefaultGlyphService;
import org.geotoolkit.font.FontAwesomeIcons;
import org.geotoolkit.font.IconBuilder;
import org.geotoolkit.gui.swing.resource.MessageBundle;
import org.geotoolkit.gui.swing.util.ActionCell;
import org.geotoolkit.gui.swing.util.JOptionDialog;
import org.geotoolkit.map.MapLayer;
import org.geotoolkit.style.StyleConstants;
import org.jdesktop.swingx.JXTable;
import org.opengis.metadata.citation.OnlineResource;
import org.opengis.style.ExternalGraphic;
import org.opengis.style.Graphic;
import org.opengis.style.GraphicalSymbol;
import org.opengis.style.Mark;
import org.opengis.style.PointSymbolizer;
import org.opengis.util.InternationalString;
/**
* graphic symbol table
*
* @author Johann Sorel
* @module
*/
public class JGraphicSymbolTable <T> extends StyleElementEditor<List> {
private static final Icon ICO_ADD = IconBuilder.createIcon(FontAwesomeIcons.ICON_PLUS, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final Icon ICO_EDIT = IconBuilder.createIcon(FontAwesomeIcons.ICON_PENCIL, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final ImageIcon ICO_UP = IconBuilder.createIcon(FontAwesomeIcons.ICON_CHEVRON_UP, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final ImageIcon ICO_DOWN = IconBuilder.createIcon(FontAwesomeIcons.ICON_CHEVRON_DOWN, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final ImageIcon ICO_DELETE = IconBuilder.createIcon(FontAwesomeIcons.ICON_TRASH_O, 16, FontAwesomeIcons.DEFAULT_COLOR);
private MapLayer layer = null;
private final GraphicalModel model = new GraphicalModel(null);
public JGraphicSymbolTable() {
super(List.class);
initComponents();
tabGraphics.setTableHeader(null);
tabGraphics.setModel(model);
tabGraphics.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
tabGraphics.getColumn(0).setCellRenderer(new GraphicRenderer());
tabGraphics.getColumn(1).setCellRenderer(new ActionCell.Renderer(ICO_UP));
tabGraphics.getColumn(1).setCellEditor(new ActionCell.Editor(ICO_UP) {
@Override
public void actionPerformed(final ActionEvent e, Object value) {
final GraphicalSymbol graphic = (GraphicalSymbol) value;
model.moveUp(graphic);
}
});
tabGraphics.getColumn(2).setCellRenderer(new ActionCell.Renderer(ICO_DOWN));
tabGraphics.getColumn(2).setCellEditor(new ActionCell.Editor(ICO_DOWN) {
@Override
public void actionPerformed(final ActionEvent e, Object value) {
final GraphicalSymbol graphic = (GraphicalSymbol) value;
model.moveDown(graphic);
}
});
tabGraphics.getColumn(3).setCellRenderer(new ActionCell.Renderer(ICO_EDIT));
tabGraphics.getColumn(3).setCellEditor(new ActionCell.Editor(ICO_EDIT) {
@Override
public void actionPerformed(final ActionEvent e, Object value) {
GraphicalSymbol symbol = (GraphicalSymbol) value;
final GraphicalSymbol oldMark = symbol;
final StyleElementEditor editor;
if(symbol instanceof Mark){
editor = new JMarkPane();
editor.parse(value);
}else{
editor = new JExternalGraphicPane();
editor.parse(value);
}
editor.setLayer(layer);
final int res = JOptionDialog.show(JGraphicSymbolTable.this, editor, JOptionPane.OK_CANCEL_OPTION);
if(JOptionPane.OK_OPTION == res){
symbol = (GraphicalSymbol) editor.create();
final List<GraphicalSymbol> symbols = model.getGraphics();
symbols.add(symbols.indexOf(oldMark),symbol);
symbols.remove(oldMark);
model.setGraphics(symbols);
}
}
});
tabGraphics.getColumn(4).setCellRenderer(new ActionCell.Renderer(ICO_DELETE));
tabGraphics.getColumn(4).setCellEditor(new ActionCell.Editor(ICO_DELETE) {
@Override
public void actionPerformed(final ActionEvent e, Object value) {
final GraphicalSymbol graphic = (GraphicalSymbol) value;
model.deleteGraphical(graphic);
}
});
final int width = 30;
tabGraphics.getColumn(1).setMinWidth(width);
tabGraphics.getColumn(1).setPreferredWidth(width);
tabGraphics.getColumn(1).setMaxWidth(width);
tabGraphics.getColumn(2).setMinWidth(width);
tabGraphics.getColumn(2).setPreferredWidth(width);
tabGraphics.getColumn(2).setMaxWidth(width);
tabGraphics.getColumn(3).setMinWidth(width);
tabGraphics.getColumn(3).setPreferredWidth(width);
tabGraphics.getColumn(3).setMaxWidth(width);
tabGraphics.getColumn(4).setMinWidth(width);
tabGraphics.getColumn(4).setPreferredWidth(width);
tabGraphics.getColumn(4).setMaxWidth(width);
tabGraphics.setTableHeader(null);
tabGraphics.setRowHeight(30);
tabGraphics.setFillsViewportHeight(true);
tabGraphics.setBackground(Color.WHITE);
tabGraphics.setShowGrid(true);
tabGraphics.setShowHorizontalLines(true);
tabGraphics.setShowVerticalLines(false);
model.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
firePropertyChange(PROPERTY_UPDATED, null, create());
}
});
}
@Override
public void setLayer(final MapLayer layer) {
this.layer = layer;
}
@Override
public MapLayer getLayer() {
return layer;
}
@Override
public void parse(final List graphics) {
model.setGraphics(graphics);
}
@Override
public List<GraphicalSymbol> create() {
return model.getGraphics();
}
@Override
protected Object[] getFirstColumnComponents() {
return new Object[]{};
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jPanel1 = new JPanel();
guiAddMark = new JButton();
guiAddExternal = new JButton();
jScrollPane2 = new JScrollPane();
tabGraphics = new JXTable();
setOpaque(false);
setLayout(new BorderLayout());
jPanel1.setLayout(new GridLayout(1, 2, 10, 0));
guiAddMark.setIcon(ICO_ADD);
guiAddMark.setText(MessageBundle.format("new_mark")); // NOI18N
guiAddMark.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
guiAddMarkActionPerformed(evt);
}
});
jPanel1.add(guiAddMark);
guiAddExternal.setIcon(ICO_ADD);
guiAddExternal.setText(MessageBundle.format("new_external")); // NOI18N
guiAddExternal.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
guiAddExternalActionPerformed(evt);
}
});
jPanel1.add(guiAddExternal);
add(jPanel1, BorderLayout.SOUTH);
jScrollPane2.setViewportView(tabGraphics);
add(jScrollPane2, BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
private void guiAddMarkActionPerformed(ActionEvent evt) {//GEN-FIRST:event_guiAddMarkActionPerformed
model.newMark();
}//GEN-LAST:event_guiAddMarkActionPerformed
private void guiAddExternalActionPerformed(ActionEvent evt) {//GEN-FIRST:event_guiAddExternalActionPerformed
model.newExternal();
}//GEN-LAST:event_guiAddExternalActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private JButton guiAddExternal;
private JButton guiAddMark;
private JPanel jPanel1;
private JScrollPane jScrollPane2;
private JXTable tabGraphics;
// End of variables declaration//GEN-END:variables
private static class GraphicalModel extends AbstractTableModel {
private final List<GraphicalSymbol> graphics = new ArrayList<GraphicalSymbol>();
GraphicalModel(final List<GraphicalSymbol> graphs) {
if (graphs != null) {
this.graphics.addAll(graphs);
}
}
public void newMark() {
final GraphicalSymbol m = getStyleFactory().mark(
getFilterFactory().literal("circle"),
StyleConstants.DEFAULT_FILL,
StyleConstants.DEFAULT_STROKE);
graphics.add(m);
int last = graphics.size() - 1;
fireTableRowsInserted(last, last);
}
public void newExternal() {
final GraphicalSymbol m;
try {
m = getStyleFactory().externalGraphic(new URL("file:/..."), "image/png");
} catch (MalformedURLException ex) {
//won't happen
throw new RuntimeException(ex.getMessage(),ex);
}
graphics.add(m);
int last = graphics.size() - 1;
fireTableRowsInserted(last, last);
}
public void deleteGraphical(final GraphicalSymbol graphic) {
final int index = graphics.indexOf(graphic);
if (index >= 0) {
graphics.remove(index);
fireTableRowsDeleted(index, index);
}
}
public void moveUp(final GraphicalSymbol m) {
int index = graphics.indexOf(m);
if (index != 0) {
graphics.remove(m);
graphics.add(index - 1, m);
fireTableDataChanged();
}
}
public void moveDown(final GraphicalSymbol m) {
int index = graphics.indexOf(m);
if (index != graphics.size() - 1) {
graphics.remove(m);
graphics.add(index + 1, m);
fireTableDataChanged();
}
}
public void setGraphics(final List<GraphicalSymbol> marks) {
if(this.graphics.equals(marks)){
//nothing changed
return;
}
this.graphics.clear();
this.graphics.addAll(marks);
fireTableDataChanged();
}
public List<GraphicalSymbol> getGraphics() {
return new ArrayList<GraphicalSymbol>(this.graphics);
}
@Override
public int getRowCount() {
return graphics.size();
}
@Override
public int getColumnCount() {
return 5;
}
@Override
public boolean isCellEditable(final int rowIndex, final int columnIndex) {
return columnIndex > 0;
}
@Override
public Class<?> getColumnClass(final int columnIndex) {
return Mark.class;
}
@Override
public Object getValueAt(final int rowIndex, final int columnIndex) {
return graphics.get(rowIndex);
}
}
private static class GraphicRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
final JLabel lbl = (JLabel) super.getTableCellRendererComponent(table, "", isSelected, hasFocus, row, column);
lbl.setIcon(null);
if(value instanceof GraphicalSymbol){
final List<GraphicalSymbol> lst = new ArrayList<>();
lst.add((GraphicalSymbol)value);
final Graphic gra = GO2Utilities.STYLE_FACTORY.graphic(
lst,
StyleConstants.DEFAULT_GRAPHIC_OPACITY,
GO2Utilities.FILTER_FACTORY.literal(16),
StyleConstants.DEFAULT_GRAPHIC_ROTATION,
StyleConstants.DEFAULT_ANCHOR_POINT,
StyleConstants.DEFAULT_DISPLACEMENT);
final PointSymbolizer ps = GO2Utilities.STYLE_FACTORY.pointSymbolizer(gra, null);
final BufferedImage image = DefaultGlyphService.create(ps, new Dimension(18, 18), null);
lbl.setIcon(new ImageIcon(image));
}
if (value instanceof Mark) {
final Mark m = (Mark) value;
lbl.setText(m.getWellKnownName().toString());
} else if (value instanceof ExternalGraphic) {
final ExternalGraphic m = (ExternalGraphic) value;
final OnlineResource res = m.getOnlineResource();
if(res != null && res.getLinkage() != null){
final InternationalString name = res.getName();
lbl.setText(name != null ? name.toString() : null);
}else{
lbl.setText("");
}
}
return lbl;
}
}
}