/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010, 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.propertyedit;
import com.vividsolutions.jts.geom.Geometry;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.TreePath;
import org.apache.sis.feature.FeatureExt;
import org.geotoolkit.util.NamesExt;
import org.geotoolkit.gui.swing.util.EmptyCellRenderer;
import org.geotoolkit.gui.swing.util.JOptionDialog;
import org.geotoolkit.gui.swing.propertyedit.featureeditor.*;
import org.geotoolkit.gui.swing.resource.IconBundle;
import org.geotoolkit.gui.swing.tree.DefaultMutableTreeNode;
import org.geotoolkit.gui.swing.tree.MutableTreeNode;
import org.apache.sis.util.Classes;
import org.geotoolkit.font.FontAwesomeIcons;
import org.geotoolkit.font.IconBuilder;
import org.jdesktop.swingx.table.DatePickerCellEditor;
import org.netbeans.swing.outline.*;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.util.GenericName;
import org.opengis.util.InternationalString;
import org.apache.sis.util.logging.Logging;
import org.opengis.feature.Feature;
/**
* Property editor, can edit Feature/Complex attribut or single properties.
* Additionaly Parameter can be edited since their model is close.
*
* @author Johann Sorel (Puzzle-GIS)
* @module
*/
public class JFeatureOutLine extends Outline{
private static final ImageIcon ICON_ADD = IconBuilder.createIcon(FontAwesomeIcons.ICON_CIRCLE_O, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final ImageIcon ICON_REMOVE = IconBuilder.createIcon(FontAwesomeIcons.ICON_CIRCLE, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final ImageIcon ICON_OCC_ADD = IconBuilder.createIcon(FontAwesomeIcons.ICON_PLUS_SQUARE, 16, FontAwesomeIcons.DEFAULT_COLOR);
private static final ImageIcon ICON_OCC_REMOVE = IconBuilder.createIcon(FontAwesomeIcons.ICON_MINUS_SQUARE, 16, FontAwesomeIcons.DEFAULT_COLOR);
private final List<PropertyValueEditor> editors = new CopyOnWriteArrayList<PropertyValueEditor>();
private final JFeatureOutLine.PropertyRowModel rowModel = new JFeatureOutLine.PropertyRowModel();
private FeatureTreeModel treeModel = null;
private Feature edited = null;
public JFeatureOutLine(){
setRenderDataProvider(new JFeatureOutLine.PropertyDataProvider());
setShowHorizontalLines(false);
//setColumnSelectionAllowed(false);
setFillsViewportHeight(true);
setBackground(Color.WHITE);
getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
editors.addAll(JAttributeEditor.createDefaultEditorList());
}
/**
* Set the property to display in this component.
*/
public void setEdited(final Feature property){
this.edited = property;
treeModel = new FeatureTreeModel(property);
if(SwingUtilities.isEventDispatchThread()){
updateModel(treeModel, property);
}else{
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
updateModel(treeModel, property);
}
});
} catch (InterruptedException | InvocationTargetException ex) {
Logging.getLogger("org.geotoolkit.gui.swing.propertyedit").log(Level.SEVERE, null, ex);
}
}
}
private void updateModel(final FeatureTreeModel treeModel,final Feature prop){
setModel(DefaultOutlineModel.createOutlineModel(treeModel, rowModel));
getColumnModel().getColumn(0).setHeaderValue(" ");
getColumnModel().getColumn(0).setResizable(true);
getColumnModel().getColumn(1).setResizable(true);
getColumnModel().getColumn(2).setMinWidth(36);
getColumnModel().getColumn(2).setMaxWidth(36);
getColumnModel().getColumn(2).setResizable(false);
}
/**
* Get the property displayed in this component.
*/
public Feature getEdited(){
return edited;
}
/**
* Set the property to display in this component. Parameters are not the
* natural model expected, but since Parameters are close to Features. An
* automatic translation is done.
*/
public void setEdited(final ParameterValueGroup parameter) {
setEdited(FeatureExt.toFeature(parameter));
}
/**
* Return the edited property as a Parameter
*
* @param desc parameter descriptor
* @return ParameterValueGroup
*/
public ParameterValueGroup getEditedAsParameter(final ParameterDescriptorGroup desc) {
return FeatureExt.toParameter(edited, desc);
}
/**
* @return live list of property editors.
*/
public List<PropertyValueEditor> getEditors() {
return editors;
}
@Override
public TableCellEditor getCellEditor(final int row, final int column) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
@Override
public TableCellEditor getDefaultEditor(final Class<?> columnClass) {
if(columnClass != null && Date.class.isAssignableFrom(columnClass)){
return new DatePickerCellEditor();
}
return super.getDefaultEditor(columnClass);
}
@Override
public TableCellRenderer getCellRenderer(final int row, final int column) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
private class PropertyRowModel implements RowModel{
@Override
public int getColumnCount() {
return 2;
}
@Override
public Object getValueFor(final Object o, final int i) {
return (MutableTreeNode) o;
}
@Override
public Class getColumnClass(final int i) {
return Object.class;
}
@Override
public boolean isCellEditable(final Object o, final int i) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
@Override
public void setValueFor(final Object o, final int i, final Object value) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
@Override
public String getColumnName(final int i) {
return "";
}
}
public static class PropertyDataProvider implements RenderDataProvider {
@Override
public java.awt.Color getBackground(final Object o) {
return null;
}
@Override
public String getDisplayName(final Object o) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
@Override
public java.awt.Color getForeground(final Object o) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
@Override
public javax.swing.Icon getIcon(final Object o) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
@Override
public String getTooltipText(final Object o) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
@Override
public boolean isHtmlDisplayName(final Object o) {
return true;
}
}
private final class GeometryCellRenderer extends DefaultOutlineCellRenderer{
@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,value,isSelected,hasFocus,row,column);
if(value instanceof Geometry || value instanceof org.opengis.geometry.Geometry){
lbl.setText("~");
}
return lbl;
}
}
private final class ActionCellRenderer extends DefaultOutlineCellRenderer {
@Override
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
return getActionComponent((JFeatureOutLine)table,value);
}
}
private final class ActionCellEditor extends AbstractCellEditor implements TableCellEditor{
@Override
public Component getTableCellEditorComponent(final JTable table, final Object value,
final boolean isSelected, final int row, final int column) {
Component comp = getActionComponent((JFeatureOutLine)table, value);
if(comp instanceof JButton){
((JButton)comp).addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
return comp;
}
@Override
public Object getCellEditorValue() {
return null;
}
}
public Component getActionComponent(final JFeatureOutLine outline, final Object value) {
//TODO editor obsolete with new feature api
throw new RuntimeException("Editor do not support new feature API yet.");
}
public static void show(Component parent, final Feature candidate){
show(parent, candidate, false);
}
public static void show(Component parent, final Feature candidate, boolean modal){
final JFeatureOutLine outline = new JFeatureOutLine();
outline.setEdited(candidate);
JOptionDialog.show(parent, outline, JOptionPane.OK_OPTION);
}
}