All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.gov.nasa.worldwindx.applications.sar.PositionTable Maven / Gradle / Ivy

Go to download

World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.

There is a newer version: 2.0.0-986
Show newest version
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */
package gov.nasa.worldwindx.applications.sar;

import gov.nasa.worldwind.geom.Angle;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.awt.*;
import java.beans.*;
import java.text.NumberFormat;

/**
 * @author tag
 * @version $Id: PositionTable.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class PositionTable extends JTable
{
    private static final int ITEM_NUM_COLUMN = 0;
    private static final int LATITUDE_COLUMN = 1;
    private static final int LONGITUDE_COLUMN = 2;
    private static final int ALTITUDE_COLUMN = 3;

    private SARTrack sarTrack;
    private String elevationUnit;
    private String angleFormat;

    private final PropertyChangeListener propertyListener = new PropertyChangeListener()
    {
        public void propertyChange(PropertyChangeEvent propertyChangeEvent)
        {
            Object newValue = propertyChangeEvent.getNewValue();
            if (newValue != null && newValue instanceof Integer)
            {
                updateTableRow((Integer) newValue);
            }
            else
            {
                updateTableData();
            }
        }
    };

    public PositionTable()
    {
        this.setToolTipText("Track Positions");
        this.setModel(new MyTableModel(this));

        // Force the JTable to commit a cell edit if that cell looses focus.
        this.putClientProperty("terminateEditOnFocusLost", true);

        TableCellRenderer tcr = this.getTableHeader().getDefaultRenderer();

        // Setup latitude and longitude columns
        this.getTableHeader().getColumnModel().getColumn(LATITUDE_COLUMN).setHeaderRenderer(
            new AngleHeaderRenderer(tcr, this));
        this.getTableHeader().getColumnModel().getColumn(LONGITUDE_COLUMN).setHeaderRenderer(
            new AngleHeaderRenderer(tcr, this));
        this.getColumnModel().getColumn(LATITUDE_COLUMN).setCellRenderer(new AngleCellRenderer(this));
        this.getColumnModel().getColumn(LONGITUDE_COLUMN).setCellRenderer(new AngleCellRenderer(this));
        this.getColumnModel().getColumn(LATITUDE_COLUMN).setCellEditor(new AngleCellEditor(this, -90, 90));
        this.getColumnModel().getColumn(LONGITUDE_COLUMN).setCellEditor(new AngleCellEditor(this, -180, 180));

        // Setup altitude column
        this.getTableHeader().getColumnModel().getColumn(ALTITUDE_COLUMN).setHeaderRenderer(
            new AltitudeHeaderRenderer(tcr, this));
        this.getColumnModel().getColumn(ALTITUDE_COLUMN).setCellRenderer(new AltitudeCellRenderer(this));
        this.getColumnModel().getColumn(ALTITUDE_COLUMN).setCellEditor(new AltitudeCellEditor(this));

        {
            TableColumnModel cm = this.getColumnModel();
            cm.getColumn(0).setResizable(false);
            cm.getColumn(0).setMinWidth(35);
            cm.getColumn(0).setPreferredWidth(35);

            cm.getColumn(1).setResizable(false);
            cm.getColumn(1).setMinWidth(70);
            cm.getColumn(1).setPreferredWidth(80);

            cm.getColumn(2).setResizable(false);
            cm.getColumn(2).setMinWidth(70);
            cm.getColumn(2).setPreferredWidth(80);

            cm.getColumn(3).setResizable(false);
            cm.getColumn(3).setMinWidth(70);
            cm.getColumn(3).setPreferredWidth(70);
        }
    }

    public SARTrack getSarTrack()
    {
        return sarTrack;
    }

    public void setSarTrack(SARTrack sarTrack)
    {
        if (this.sarTrack == sarTrack)
            return;

        if (this.sarTrack != null)
            this.sarTrack.removePropertyChangeListener(this.propertyListener);

        this.sarTrack = sarTrack;

        if (this.sarTrack != null)
            this.sarTrack.addPropertyChangeListener(this.propertyListener);

        this.setTableColors(this.sarTrack);
        this.updateTableData();
    }

    public String getElevationUnit()
    {
        return this.elevationUnit;
    }

    public void setElevationUnit(String unit)
    {
        this.elevationUnit = unit;
    }

    public String getAngleFormat()
    {
        return this.angleFormat;
    }

    public void setAngleFormat(String format)
    {
        this.angleFormat = format;
    }

    public void updateTableData()
    {
        ((AbstractTableModel) this.getModel()).fireTableDataChanged();
    }

    public void updateTableRow(int row)
    {
        ((AbstractTableModel) this.getModel()).fireTableRowsUpdated(row, row);
    }

    protected Color getTableColorForTrack(SARTrack track)
    {
        if (track == null)
            return null;

        Color color = track.getColor();

        float[] hsbComponents = new float[3];
        Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsbComponents);
        float hue = hsbComponents[0];
        float saturation = hsbComponents[1];
        float brightness = hsbComponents[2];

        saturation *= 0.2f;
        
        int rgbInt = Color.HSBtoRGB(hue, saturation, brightness);

        return new Color(rgbInt);
    }

    protected void setTableColors(SARTrack track)
    {
        Color tableBackground = this.getTableColorForTrack(track);
        Color selectionBackground = (tableBackground != null) ? Color.DARK_GRAY : null;
        Color selectionForeground = (tableBackground != null) ? Color.WHITE : null;

        this.setBackground(tableBackground);
        this.setSelectionForeground(selectionForeground);
        this.setSelectionBackground(selectionBackground);
        this.setOpaque(true);

        Container c = this.getParent();
        if (c != null)
        {
            c.setBackground(tableBackground);
            if (c instanceof JComponent)
                ((JComponent) c).setOpaque(true);
        }
    }

    private class MyTableModel extends AbstractTableModel
    {
        String[] columnNames = new String[] {
            "#", "Latitude", "Longitude", "Altitude"
        };

        Class[] columnTypes = new Class[] {
            Integer.class, String.class, String.class, Double.class
        };

        boolean[] columnEditable = new boolean[] {
            false, true, true, true
        };

        private PositionTable table;

        public MyTableModel(PositionTable table)
        {
            this.table = table;
        }

        @Override
        public Class getColumnClass(int columnIndex)
        {
            return this.columnTypes[columnIndex];
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex)
        {
            return this.columnEditable[columnIndex];
        }

        public int getRowCount()
        {
            return sarTrack != null ? sarTrack.size() : 0;
        }

        @Override
        public String getColumnName(int columnIndex)
        {
            return this.columnNames[columnIndex];
        }

        public int getColumnCount()
        {
            return 4;
        }

        public Object getValueAt(int row, int col)
        {
            if (sarTrack == null)
                return null;

            switch (col)
            {
                case ITEM_NUM_COLUMN:
                    return row;
                case LATITUDE_COLUMN:
                    return sarTrack.get(row).getLatitude().degrees;
                case LONGITUDE_COLUMN:
                    return sarTrack.get(row).getLongitude().degrees;
                case ALTITUDE_COLUMN:
                    return sarTrack.get(row).getElevation();
            }

            return null;
        }

        @Override
        public void setValueAt(Object object, int row, int col)
        {
            if (sarTrack == null)
                return;

            SARPosition curPos = sarTrack.get(row);
            SARPosition newPos;
            Angle newAngle;

            switch (col)
            {
                case LATITUDE_COLUMN:
                    if (!(object instanceof String))
                        return;
                    if ((newAngle = table.toAngle((String) object)) == null)
                        return;
                    newPos = new SARPosition(newAngle, curPos.getLongitude(), curPos.getElevation());
                    break;
                case LONGITUDE_COLUMN:
                    if (!(object instanceof String))
                        return;
                    if ((newAngle = table.toAngle((String) object)) == null)
                        return;
                    newPos = new SARPosition(curPos.getLatitude(), newAngle, curPos.getElevation());
                    break;
                case ALTITUDE_COLUMN:
                    // The value stored in a SARPosition's elevation will always be in meters.
                    // So when the altitude is displayed in feet, we will convert the incoming
                    // value back to meters. This allows the user entring a value to operate in
                    // whatever units are being displayed without thinking about conversion.
                    if (!(object instanceof Double))
                        return;
                    double newVal = (Double) object;
                    if (SAR2.UNIT_IMPERIAL.equals(elevationUnit))
                        newVal = SAR2.feetToMeters(newVal);
                    newPos = new SARPosition(curPos.getLatitude(), curPos.getLongitude(), newVal);
                    break;
                default:
                    return;
            }

            sarTrack.set(row, newPos);
        }
    }

    private Angle toAngle(String string)
    {
        if (Angle.ANGLE_FORMAT_DMS.equals(this.angleFormat))
        {
            try
            {
                return Angle.fromDMS(string);
            }
            catch (Exception ignore)
            {
                return null;
            }
        }
        else
        {
            try
            {
                Number number = NumberFormat.getInstance().parse(string.trim());
                return Angle.fromDegrees(number.doubleValue());
            }
            catch (Exception ignore)
            {
                return null;
            }
        }
    }

    private String makeAngleDescription(double degrees)
    {
        return SAR2.formatAngle(this.angleFormat, Angle.fromDegrees(degrees));
    }

    private String makeElevationDescription(double metersElevation)
    {
        String s;
        if (SAR2.UNIT_IMPERIAL.equals(this.elevationUnit))
            s = NumberFormat.getInstance().format(SAR2.metersToFeet(metersElevation));
        else // Default to metric units.
            s = NumberFormat.getInstance().format(metersElevation);
        return s;
    }

    private static class AltitudeHeaderRenderer implements TableCellRenderer
    {
        private TableCellRenderer delegate;
        private PositionTable table;

        public AltitudeHeaderRenderer(TableCellRenderer delegate, PositionTable table)
        {
            this.delegate = delegate;
            this.table = table;
        }

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
            int row, int column)
        {
            if (this.delegate == null)
                return null;

            Component c = this.delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (c == null || !(c instanceof JLabel))
                return c;

            JLabel label = (JLabel) c;
            if (label.getText() == null)
                return c;

            if (SAR2.UNIT_IMPERIAL.equals(this.table.elevationUnit))
                label.setText(label.getText() + " (ft)");
            else // Default to metric units.
                label.setText(label.getText() + " (m)");
            return label;
        }
    }

    private static class AngleHeaderRenderer implements TableCellRenderer
    {
        private TableCellRenderer delegate;
        private PositionTable table;

        public AngleHeaderRenderer(TableCellRenderer delegate, PositionTable table)
        {
            this.delegate = delegate;
            this.table = table;
        }

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
            int row, int column)
        {
            if (this.delegate == null)
                return null;

            Component c = this.delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (c == null || !(c instanceof JLabel))
                return c;

            JLabel label = (JLabel) c;
            if (label.getText() == null)
                return c;

            if (Angle.ANGLE_FORMAT_DMS.equals(this.table.angleFormat))
                label.setText(label.getText() + " (dms)");
            else // Default to decimal degrees.
                label.setText(label.getText() + " (dd)");
            return label;
        }
    }

    private static class AngleCellRenderer extends DefaultTableCellRenderer
    {
        private PositionTable table;

        private AngleCellRenderer(PositionTable table)
        {
            this.table = table;
            setHorizontalAlignment(SwingConstants.RIGHT);
        }

        public void setValue(Object value)
        {
            setText(value != null ? this.table.makeAngleDescription((Double) value) : "");
        }
    }

    private static class AltitudeCellRenderer extends DefaultTableCellRenderer
    {
        private PositionTable table;

        private AltitudeCellRenderer(PositionTable table)
        {
            this.table = table;
            setHorizontalAlignment(SwingConstants.RIGHT);
        }

        protected void setValue(Object value)
        {
            setText(this.table.makeElevationDescription((Double) value));
        }
    }

    private static class GeneralCellEditor extends DefaultCellEditor
    {
        private PositionTable table;
        private Object value;

        public GeneralCellEditor(JTextField textField, PositionTable table)
        {
            super(textField);
            this.table = table;
        }

        public PositionTable getTable()
        {
            return table;
        }

        public Object getCellEditorValue()
        {
            return this.value;
        }

        public boolean stopCellEditing()
        {
            String s = (String) super.getCellEditorValue();
            try
            {
                this.value = this.validateEditorText(s);
            }
            catch (Exception e)
            {
                ((JComponent) getComponent()).setBorder(new LineBorder(Color.red));
                return false;
            }
            return super.stopCellEditing();
        }

        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
            int row, int column)
        {
            ((JComponent) getComponent()).setBorder(new LineBorder(Color.black));
            this.value = null;
            try
            {
                this.value = this.createEditorText(value);
            }
            catch (Exception e)
            {
                return null;
            }
            return super.getTableCellEditorComponent(table, this.value, isSelected, row, column);
        }

        protected Object validateEditorText(String text) throws Exception
        {
            return text;
        }

        protected String createEditorText(Object value) throws Exception
        {
            return value.toString();
        }
    }

    private class AngleCellEditor extends GeneralCellEditor
    {
        double min, max;

        public AngleCellEditor(PositionTable table, double min, double max)
        {
            super(new JTextField(), table);
            this.min = min;
            this.max = max;
            ((JTextField) getComponent()).setHorizontalAlignment(JTextField.RIGHT);
        }

        protected Object validateEditorText(String text) throws Exception
        {
            Angle angle = this.getTable().toAngle(text);
            if (angle == null)
                throw new IllegalArgumentException(text);
            if (angle.degrees < min || angle.degrees > max)
                throw new IllegalArgumentException(text);
            return text;
        }

        protected String createEditorText(Object value) throws Exception
        {
            String text = this.getTable().makeAngleDescription((Double) value);
            text = text.replaceAll("[D|d|\u00B0|'|\u2019|\"|\u201d]", " ").replaceAll("\\s+", " ");
            return text;
        }
    }

    private static class AltitudeCellEditor extends GeneralCellEditor
    {
        public AltitudeCellEditor(PositionTable table)
        {
            super(new JTextField(), table);
            ((JTextField) getComponent()).setHorizontalAlignment(JTextField.RIGHT);
        }

        protected Object validateEditorText(String text) throws Exception
        {
            Number number = NumberFormat.getInstance().parse(text);
            return number.doubleValue();
        }

        protected String createEditorText(Object value) throws Exception
        {
            return this.getTable().makeElevationDescription((Double) value);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy