/* * Copyright (C) 2012 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program 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 General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.snap.unmixing.ui; import org.esa.snap.core.util.ResourceInstaller; import org.esa.snap.core.util.SystemUtils; import org.esa.snap.core.util.io.SnapFileFilter; import org.esa.snap.runtime.Config; import org.esa.snap.tango.TangoIcons; import org.esa.snap.ui.AppContext; import org.esa.snap.ui.diagram.DefaultDiagramGraphStyle; import org.esa.snap.ui.diagram.Diagram; import org.esa.snap.ui.diagram.DiagramAxis; import org.esa.snap.ui.diagram.DiagramGraph; import org.esa.snap.ui.diagram.DiagramGraphIO; import org.esa.snap.unmixing.Endmember; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.DefaultListModel; import javax.swing.DefaultListSelectionModel; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.BasicStroke; import java.awt.Color; import java.awt.event.ActionEvent; import java.beans.PropertyChangeSupport; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.prefs.Preferences; class EndmemberFormModel { private DefaultListModel<Endmember> endmemberListModel; private DefaultListSelectionModel endmemberListSelectionModel; private int selectedEndmemberIndex; private Diagram endmemberDiagram; private Action addAction = new AddAction(); private Action removeAction = new RemoveAction(); private Action clearAction = new ClearAction(); private Action exportAction = new ExportAction(); private AppContext appContext; private PropertyChangeSupport propertyChangeSupport; private Color[] defaultColors = new Color[]{Color.BLACK, Color.RED.darker(), Color.GREEN.darker(), Color.BLUE.darker(), Color.YELLOW}; private static Path defaultEndmemberDir = SystemUtils.getAuxDataPath().resolve("unmix"); public EndmemberFormModel(AppContext appContext) { this.appContext = appContext; endmemberListModel = new DefaultListModel<>(); endmemberListSelectionModel = new DefaultListSelectionModel(); endmemberListSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); endmemberListModel.addListDataListener(new EndmemberListDataListener()); endmemberListSelectionModel.addListSelectionListener(new EndmemberListSelectionListener()); endmemberDiagram = new Diagram(); endmemberDiagram.setXAxis(new DiagramAxis("Wavelength", "")); endmemberDiagram.setYAxis(new DiagramAxis("Radiation", "")); endmemberDiagram.setDrawGrid(false); propertyChangeSupport = new PropertyChangeSupport(this); } public Endmember[] getEndmembers() { Endmember[] endmembers = new Endmember[endmemberListModel.getSize()]; for (int i = 0; i < endmembers.length; i++) { endmembers[i] = endmemberListModel.getElementAt(i); } return endmembers; } public void setEndmembers(Endmember[] endmembers) { endmemberListModel.removeAllElements(); for (Endmember endmember : endmembers) { endmemberListModel.addElement(endmember); } } public ListModel<Endmember> getEndmemberListModel() { return endmemberListModel; } public DefaultListSelectionModel getEndmemberListSelectionModel() { return endmemberListSelectionModel; } public PropertyChangeSupport getPropertyChangeSupport() { return propertyChangeSupport; } public int getSelectedEndmemberIndex() { return selectedEndmemberIndex; } public Action getAddAction() { return addAction; } public Action getRemoveAction() { return removeAction; } public Action getClearAction() { return clearAction; } public Action getExportAction() { return exportAction; } public Diagram getEndmemberDiagram() { return endmemberDiagram; } private void addEndmember(Endmember endmember) { endmemberListModel.addElement(endmember); EndmemberGraph endmemberGraph = new EndmemberGraph(endmember); Color color = defaultColors[endmemberListModel.getSize() % defaultColors.length]; DefaultDiagramGraphStyle style = ((DefaultDiagramGraphStyle) endmemberGraph.getStyle()); style.setOutlineColor(color); style.setOutlineStroke(new BasicStroke(1.0f)); style.setShowingPoints(false); endmemberDiagram.addGraph(endmemberGraph); endmemberDiagram.adjustAxes(true); } public void setSelectedEndmemberIndex(int index) { int oldIndex = selectedEndmemberIndex; if (oldIndex == index) { return; } if (oldIndex >= 0 && endmemberDiagram.getGraphCount() > 0) { final DiagramGraph endmemberGraph = endmemberDiagram.getGraph(oldIndex); ((DefaultDiagramGraphStyle) endmemberGraph.getStyle()).setOutlineStroke(new BasicStroke(1.0f)); } selectedEndmemberIndex = index; if (selectedEndmemberIndex >= 0 && endmemberDiagram.getGraphCount() > 0) { final DiagramGraph endmemberGraph = endmemberDiagram.getGraph(selectedEndmemberIndex); ((DefaultDiagramGraphStyle) endmemberGraph.getStyle()).setOutlineStroke(new BasicStroke(2.0f)); } endmemberDiagram.invalidate(); propertyChangeSupport.firePropertyChange("selectedEndmemberIndex", oldIndex, selectedEndmemberIndex); } private void ensureDefaultDirSet() { if (!Files.exists(defaultEndmemberDir)) { Path sourceDirPath = ResourceInstaller.findModuleCodeBasePath(SpectralUnmixingDialog.class).resolve("auxdata"); final ResourceInstaller resourceInstaller = new ResourceInstaller(sourceDirPath, defaultEndmemberDir); try { resourceInstaller.install(".*", com.bc.ceres.core.ProgressMonitor.NULL); } catch (IOException e) { // failed, so what } } final String key = DiagramGraphIO.DIAGRAM_GRAPH_IO_LAST_DIR_KEY; final Preferences preferences = Config.instance().preferences(); if (preferences.get(key, null) == null) { preferences.put(key, defaultEndmemberDir.toAbsolutePath().toString()); } } private class AddAction extends AbstractAction { public AddAction() { super("Add"); putValue(LARGE_ICON_KEY, TangoIcons.actions_list_add(TangoIcons.Res.R16)); putValue(SHORT_DESCRIPTION, "Add Endmembers"); } public void actionPerformed(ActionEvent e) { ensureDefaultDirSet(); DiagramGraph[] diagramGraphs = DiagramGraphIO.readGraphs(null, "Add Endmembers", new SnapFileFilter[]{DiagramGraphIO.SPECTRA_CSV_FILE_FILTER}, appContext.getPreferences()); Endmember[] endmembers = convertGraphsToEndmembers(diagramGraphs); for (Endmember endmember : endmembers) { addEndmember(endmember); } } private Endmember[] convertGraphsToEndmembers(DiagramGraph[] diagramGraphs) { Endmember[] endmembers = new Endmember[diagramGraphs.length]; for (int i = 0; i < diagramGraphs.length; i++) { DiagramGraph diagramGraph = diagramGraphs[i]; int numValues = diagramGraph.getNumValues(); double[] wavelengths = new double[numValues]; double[] radiations = new double[numValues]; for (int j = 0; j < numValues; j++) { wavelengths[j] = diagramGraph.getXValueAt(j); radiations[j] = diagramGraph.getYValueAt(j); } endmembers[i] = new Endmember(diagramGraph.getYName(), wavelengths, radiations); } return endmembers; } } private class RemoveAction extends AbstractAction { public RemoveAction() { super("Remove"); putValue(LARGE_ICON_KEY, TangoIcons.actions_list_remove(TangoIcons.Res.R16)); putValue(SHORT_DESCRIPTION, "Remove Endmember"); } public void actionPerformed(ActionEvent e) { int index = selectedEndmemberIndex; if (index >= 0) { setSelectedEndmemberIndex(-1); endmemberListModel.removeElementAt(index); endmemberDiagram.removeGraph(endmemberDiagram.getGraph(index)); endmemberDiagram.adjustAxes(true); } } } private class ClearAction extends AbstractAction { public ClearAction() { super("Clear"); putValue(LARGE_ICON_KEY, TangoIcons.actions_edit_clear(TangoIcons.Res.R16)); putValue(SHORT_DESCRIPTION, "Clear List"); } public void actionPerformed(ActionEvent e) { setSelectedEndmemberIndex(-1); endmemberListModel.removeAllElements(); endmemberDiagram.removeAllGraphs(); } } private class ExportAction extends AbstractAction { public ExportAction() { super("Export"); putValue(LARGE_ICON_KEY, TangoIcons.actions_document_save_as(TangoIcons.Res.R16)); putValue(SHORT_DESCRIPTION, "Export Endmembers"); } public void actionPerformed(ActionEvent e) { ensureDefaultDirSet(); DiagramGraphIO.writeGraphs(null, "Export Endmembers", new SnapFileFilter[]{DiagramGraphIO.SPECTRA_CSV_FILE_FILTER}, appContext.getPreferences(), endmemberDiagram.getGraphs()); } } private class EndmemberListDataListener implements ListDataListener { public void intervalAdded(ListDataEvent e) { endmemberDiagram.invalidate(); } public void intervalRemoved(ListDataEvent e) { endmemberDiagram.invalidate(); } public void contentsChanged(ListDataEvent e) { endmemberDiagram.invalidate(); } } private class EndmemberListSelectionListener implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { if (endmemberListSelectionModel.isSelectionEmpty()) { setSelectedEndmemberIndex(-1); } else { setSelectedEndmemberIndex(endmemberListSelectionModel.getLeadSelectionIndex()); } } } } }