/*
* Copyright 2004-2010 Information & Software Engineering Group (188/1)
* Institute of Software Technology and Interactive Systems
* Vienna University of Technology, Austria
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.tuwien.ifs.somtoolbox.apps.viewer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import java.util.TreeSet;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.ProgressMonitor;
import javax.swing.WindowConstants;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import com.martiansoftware.jsap.JSAPResult;
import com.martiansoftware.jsap.Parameter;
import edu.umd.cs.piccolo.PLayer;
import at.tuwien.ifs.commons.gui.util.MaximisedJFrame;
import at.tuwien.ifs.somtoolbox.SOMToolboxException;
import at.tuwien.ifs.somtoolbox.SOMToolboxMetaConstants;
import at.tuwien.ifs.somtoolbox.apps.DataSetViewer;
import at.tuwien.ifs.somtoolbox.apps.PaletteEditor;
import at.tuwien.ifs.somtoolbox.apps.SOMToolboxApp;
import at.tuwien.ifs.somtoolbox.apps.config.AbstractOptionFactory;
import at.tuwien.ifs.somtoolbox.apps.config.OptionFactory;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.AbstractSelectionPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.AbstractViewerControl;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.ClassLegendPane;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.ClusteringControl;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.ComparisonPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.DocSOMPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.GHSOMNavigationPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.MapDetailPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.MapOverviewPane;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.MultichannelPlaybackPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.PalettePanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.PlaySOMPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.PlaygroundPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.QuerySOMPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.ShiftsControlPanel;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.VisualizationControl;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.player.PlaySOMPlayer;
import at.tuwien.ifs.somtoolbox.apps.viewer.controls.psomserver.PocketSOMConnector;
import at.tuwien.ifs.somtoolbox.apps.viewer.fileutils.ExportUtils;
import at.tuwien.ifs.somtoolbox.apps.viewer.fileutils.PocketSOMFormatUtils;
import at.tuwien.ifs.somtoolbox.apps.viewer.handlers.LoggingHandler;
import at.tuwien.ifs.somtoolbox.data.InputData;
import at.tuwien.ifs.somtoolbox.data.SOMLibClassInformation;
import at.tuwien.ifs.somtoolbox.data.SOMVisualisationData;
import at.tuwien.ifs.somtoolbox.data.SharedSOMVisualisationData;
import at.tuwien.ifs.somtoolbox.input.InputCorrections;
import at.tuwien.ifs.somtoolbox.input.SOMLibDataWinnerMapping;
import at.tuwien.ifs.somtoolbox.input.InputCorrections.CreationType;
import at.tuwien.ifs.somtoolbox.input.InputCorrections.InputCorrection;
import at.tuwien.ifs.somtoolbox.layers.Unit;
import at.tuwien.ifs.somtoolbox.layers.GrowingLayer.Flip;
import at.tuwien.ifs.somtoolbox.layers.GrowingLayer.Rotation;
import at.tuwien.ifs.somtoolbox.layers.Unit.FeatureWeightMode;
import at.tuwien.ifs.somtoolbox.models.GrowingSOM;
import at.tuwien.ifs.somtoolbox.output.SOMLibMapOutputter;
import at.tuwien.ifs.somtoolbox.properties.PropertiesException;
import at.tuwien.ifs.somtoolbox.properties.SOMViewerProperties;
import at.tuwien.ifs.somtoolbox.reportgenerator.ReportGenerator;
import at.tuwien.ifs.somtoolbox.util.FileUtils;
import at.tuwien.ifs.somtoolbox.util.JMultiLineRadioButtonMenuItem;
import at.tuwien.ifs.somtoolbox.util.SwingWorker;
import at.tuwien.ifs.somtoolbox.util.UiUtils;
import at.tuwien.ifs.somtoolbox.visualization.AbstractBackgroundImageVisualizer;
import at.tuwien.ifs.somtoolbox.visualization.AbstractMatrixVisualizer;
import at.tuwien.ifs.somtoolbox.visualization.BackgroundImageVisualizer;
import at.tuwien.ifs.somtoolbox.visualization.BackgroundImageVisualizerInstance;
import at.tuwien.ifs.somtoolbox.visualization.ComparisonVisualizer;
import at.tuwien.ifs.somtoolbox.visualization.Palette;
import at.tuwien.ifs.somtoolbox.visualization.Palettes;
import at.tuwien.ifs.somtoolbox.visualization.QualityMeasureVisualizer;
import at.tuwien.ifs.somtoolbox.visualization.SmoothedDataHistograms;
import at.tuwien.ifs.somtoolbox.visualization.ThematicClassMapVisualizer;
import at.tuwien.ifs.somtoolbox.visualization.Visualizations;
import at.tuwien.ifs.somtoolbox.visualization.SmoothedDataHistograms.SDHControlPanel;
import at.tuwien.ifs.somtoolbox.visualization.clustering.ClusteringAbortedException;
import at.tuwien.ifs.somtoolbox.visualization.clustering.CompleteLinkageTreeBuilder;
import at.tuwien.ifs.somtoolbox.visualization.clustering.KMeansTreeBuilder;
import at.tuwien.ifs.somtoolbox.visualization.clustering.SingleLinkageTreeBuilder;
import at.tuwien.ifs.somtoolbox.visualization.clustering.TreeBuilder;
import at.tuwien.ifs.somtoolbox.visualization.clustering.WardsLinkageTreeBuilder;
import at.tuwien.ifs.somtoolbox.visualization.clustering.WardsLinkageTreeBuilderAll;
/**
* The class providing the main window of the SOMViewer application. Initialises all the control element windows (see
* {@link at.tuwien.ifs.somtoolbox.apps.viewer.controls} package), toolbars, and the {@link SOMFrame} holding the map
* representation ({@link MapPNode} ).
*
* @author Michael Dittenbach
* @author Rudolf Mayer
* @author Thomas Lidy
* @version $Id: SOMViewer.java 3919 2010-11-05 11:58:02Z mayer $
*/
public class SOMViewer extends MaximisedJFrame implements ActionListener, Observer, SOMToolboxApp {
public static final String DESCRIPTION = "An interactive viewer for exploring SOMs, using different visualisations";
public static final Type APPLICATION_TYPE = Type.Viewer;
public static final String LONG_DESCRIPTION = DESCRIPTION;
public static final Parameter[] OPTIONS = new Parameter[] {
// mandatory
OptionFactory.getOptUnitDescriptionFile(true),
OptionFactory.getOptWeightVectorFile(true),
// additional input files
OptionFactory.getOptDataWinnerMappingFile(false), OptionFactory.getOptMapDescriptionFile(false),
OptionFactory.getOptTemplateVectorFile(false), OptionFactory.getOptInputVectorFile(false),
OptionFactory.getOptClassInformationFile(false), OptionFactory.getOptRegressionInformationFile(false),
OptionFactory.getOptDataInformationFileFile(false),
OptionFactory.getOptHighlightedDataNamesFile(false),
OptionFactory.getOptLinkageFile(false),
OptionFactory.getOptInputCorrections(false),
OptionFactory.getOptClassColoursFile(false),
//
OptionFactory.getOptFileNamePrefix(false), OptionFactory.getOptFileNameSuffix(false),
OptionFactory.getOptApplicationDirectory(false),
OptionFactory.getOptViewerWorkingDir(false),
// initial vis
OptionFactory.getOptInitialVisualisation(false), OptionFactory.getOptInitialVisParams(false),
OptionFactory.getOptInitialPalette(false),
// second SOM
OptionFactory.getOptSetSecondSOM(false),
// Others
OptionFactory.getSwitchDocumentMode(), OptionFactory.getSwitchNoPlayer(),
OptionFactory.getOptDecodeProbability(false), OptionFactory.getOptDecodedOutputDir(false) };
private static final long serialVersionUID = 1L;
public static final String PREFS_FILE = "somviewer.prop";
// messages
private static final String CENTER_AND_FIT_MAP = "Center and fit map to screen";
private static final String SELECT_LINE = "Select Line Selection Handler";
private static final String SELECT_RECTANGLE = "Select Rectangle or Unit Selection Handler";
private static final String SELECT_CLUSTER = "Select Cluster Selection Handler";
private static final String RESET_DESKTOP_LAYOUT = "Reset desktop windows layout";
private static final String SOMVIEWER_3D = "Start 3D SOM Viewer";
private static final String MOVE_INPUT = "Move Input"; // rudi for semi-supervised
private static final String MOVE_LABEL = "Move Labels"; // Angela
private static final String CREATE_LABEL = "Create new Label"; // Angela
static final String TOGGLE_PIE_CHARTS_SHOW = "Pie-charts";
static final String TOGGLE_PIE_CHARTS_SHOW_COUNTS = "Pie-charts with counts";
static final String TOGGLE_PIE_CHARTS_SHOW_PERCENT = "Pie-charts with percent";
static final String TOGGLE_PIE_CHARTS_NONE = "No pie-charts";
private static final String[] TOGGLE_PIE_CHARTS_MODES = { TOGGLE_PIE_CHARTS_SHOW, TOGGLE_PIE_CHARTS_SHOW_COUNTS,
TOGGLE_PIE_CHARTS_SHOW_PERCENT, TOGGLE_PIE_CHARTS_NONE };
// icons are not static, so they don't get initialised when the class is loaded by SOMToolboxMain
// this would lead to an error on headless environments, e.g. in a 'screen'
private final ImageIcon TOGGLE_PIE_CHARTS_ICONS[] = { UiUtils.getIcon("piechart.png"),
UiUtils.getIcon("piechart_label.png"), UiUtils.getIcon("piechart_label_percent.png"),
UiUtils.getIcon("piechart_off.png") };
private static final String TOGGLE_LABELS = "Show labels";
private static final String TOGGLE_HITS = "Show hits";
private static final String TOGGLE_DATA = "Show data";
private static final String TOGGLE_EXACT_PLACEMENT = "Exact placement of input vectors";
private static final String TOGGLE_RELOCATE = "Relocate overlapping input vectors";
private static final String TOGGLE_LINKAGE = "Display input linkages";
private static final String MSG_EXACTPLACEMENT_DISABLED = "Data winner mapping file needs to be loaded for this feature!";
// resources
public static final String RESOURCE_PATH_ICONS = "rsc/icons/";
// settings
// wether to create a fullscreen gui or not
// private static final boolean fullScreen = true;
private String unitDescriptionFileName = null;
private String weightVectorFileName = null;
// private String highlightedDataNamesFileName = null;
private String mapDescriptionFileName = null;
private String classInformationFileName = null;
private String regressionInformationFileName = null;
private String dataInformationFileName = null;
private String inputVectorFileName = null;
private String templateVectorFileName;
private String dataWinnerMappingFileName = null;
private String linkageMapFileName = null;
private JFrame docViewerFrame = null;
private boolean documentMode = false;
private String viewerWorkingDirectoryName = ".";
private String applicationDirectory = ".";
private SOMViewerProperties prefs;
private LoggingHandler loggingHandler = null;
private BackgroundImageVisualizer initialVisualisation;
private int initialVisualisationVariant;
private String classColoursFile = null;
// menu
private JMenuBar menuBar = null;
private JMenu visualizationMenu = null;
private JMenu paletteMenu = null;
private ButtonGroup visualizationMenuItemGroup = null;
private ButtonGroup paletteMenuItemGroup = null;
private ButtonModel oldSelectedVisualizationMenuItem = null;
private JMultiLineRadioButtonMenuItem thematicClassRadioButton = null;
private JCheckBoxMenuItem reversePaletteMenuItem = null;
private ButtonGroup clusterMethodGroup;
private int clusteringLevel = 1;
private ButtonModel previousSelectedClusteringMethod; // previously selected item
private JMenu windowMenu;
// ToolBar
private JToolBar toolBar = null;
private JPopupMenu menuPie = new JPopupMenu();
private JButton buttonPie = new JButton();
private AbstractButton shiftOverlappingToggleButton;
private AbstractButton exactPlacementToggleButton;
private AbstractButton linkageToggleButton;
// StatusBar
private StatusBar statusBar = null;
// panes and other stuff
// private JDesktopPane desktop = new JDesktopPane();
private ClassLegendPane classLegendPane = null;
private VisualizationControl visControlPanel = null;
private ClusteringControl clusteringControl = null;
private SOMPane mapPane = null;
private PalettePanel palettePanel = null;
private ControlCollector collector = null;
private QuerySOMPanel queryPane = null;
private CommonSOMViewerStateData state = new CommonSOMViewerStateData(this, 220);
private SOMFrame somFrame = new SOMFrame(state);
// SOM Comparison stuff:
private JCheckBoxMenuItem showShiftsMenuItem = null;
private ShiftsControlPanel shiftsControlPanel = null;
private JMenu switchMapSubmenu = null;
private JMultiLineRadioButtonMenuItem useMainMap = null;
private JMultiLineRadioButtonMenuItem useSecondMap = null;
private boolean noInternalPlayer;
private Vector<VisualizationChangeListener> visChangeListeners = new Vector<VisualizationChangeListener>();
private JMenuItem paletteEditorMenuItem = null;
public static final String NO_JAVA3D_ERROR_MESSAGE = "Problem intialising Java3D!"
+ "\nPlease make sure you downloaded it from http://java3d.dev.java.net/ and installed it to the 'lib' directory of your Java Runtime (i.e. $JAVA_HOME/jre/lib)."
+ "\nAborting.";
/**
* Starts a new SOM Viewer frame.
*
* @param config Needed program arguments:
* <ul>
* <li>-u unitDescriptionFileName, mandatory</li>
* <li>-w weightVectorFileName, mandatory</li>
* <li>-l drawLines, switch</li>
* <li>-m mapDescriptionFileName, optional</li>
* <li>-c classInformationFileName, optional</li>
* <li>-r regressionInformationFileNameInformationFileName, optional</li>
* <li>-d dataNamesFilename, optional</li>
* <li>-i dataInfoFileName, optional</li>
* <li>-v inputVectorFile, optional</li>
* <li>-t templateVectorFile, optional</li>
* <li>--dw dataWinnerMappingFile, optional</li>
* <li>-t templateVectorFile, optional</li>
* <li>-p fileNamePrefix, optional</li>
* <li>-s fileNameSuffix, optional</li>
* <li>--dir viewerWorkingDirectory, optional</li>
* <li>-o documentMode, switch, default = false</li>
* <li>imageName</li>
* </ul>
* @throws HeadlessException When started in an environment that does not support a keyboard, display, or mouse.
*/
public SOMViewer(JSAPResult config) throws HeadlessException {
super();
// Look and Feel is set her, as the call to Visualizations.getAvailableVisualizations() triggers the
// initialisation of the control panels, then in the initial system look and feel (see #48, 224)
UiUtils.setSOMToolboxLookAndFeel();
setDefaultLookAndFeelDecorated(true);
// just trigger to do initialisation work as finding visualisations and palettes in the beginning
// with a current bug happening sometimes on loading the visualisation classes, this also prevents spending time
// on loading the input data,
// and then the application to hang
Visualizations.getAvailableVisualizations();
Palettes.getAvailablePalettes();
/* set handler for all logging events, which decides where to output it */
try {
loggingHandler = new LoggingHandler();
loggingHandler.setLevel(Level.FINEST);
loggingHandler.setParentComponent(this);
Logger.getLogger("at.tuwien.ifs.somtoolbox").setLevel(Level.FINEST);
Logger.getLogger("at.tuwien.ifs.somtoolbox").addHandler(loggingHandler);
} catch (SecurityException e1) {
e1.printStackTrace();
}
// Jakob Frank: init state moved here - avoids NullPointerException
state = new CommonSOMViewerStateData(this, 220);
// highlightedDataNamesFileName = config.getString("highlightedDataNamesFile");
unitDescriptionFileName = AbstractOptionFactory.getFilePath(config, "unitDescriptionFile");
weightVectorFileName = AbstractOptionFactory.getFilePath(config, "weightVectorFile");
mapDescriptionFileName = AbstractOptionFactory.getFilePath(config, "mapDescriptionFile");
classInformationFileName = AbstractOptionFactory.getFilePath(config, "classInformationFile");
regressionInformationFileName = AbstractOptionFactory.getFilePath(config, "regressionInformationFile");
dataInformationFileName = AbstractOptionFactory.getFilePath(config, "dataInformationFile");
inputVectorFileName = AbstractOptionFactory.getFilePath(config, "inputVectorFile");
templateVectorFileName = AbstractOptionFactory.getFilePath(config, "templateVectorFile");
dataWinnerMappingFileName = AbstractOptionFactory.getFilePath(config, "dataWinnerMappingFile");
linkageMapFileName = AbstractOptionFactory.getFilePath(config, "linkageMapFile");
classColoursFile = AbstractOptionFactory.getFilePath(config, "classColours");
noInternalPlayer = config.getBoolean("noplayer");
final String s = AbstractOptionFactory.getFilePath(config, "secondSOMPrefix");
if (StringUtils.isNotBlank(s)) {
final File file = new File(s).getAbsoluteFile();
if (file.getParentFile() != null && file.getParentFile().exists()) {
state.secondSOMName = file.getAbsolutePath();
// add SOM to comparison visualisation
((ComparisonVisualizer) Visualizations.getVisualizationByName("ComparisonMean").getVis()).addSOM(s);
} else {
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning(
"Couldn't find path for second some, given: '" + s + ", resolves to: '"
+ file.getAbsolutePath() + "'.");
}
}
String inputCorrectionsFileName = config.getString("inputCorrections");
if (config.getString("applicationDirectory", System.getenv("SOMTOOLBOX_BASEDIR")) != null) {
applicationDirectory = config.getString("applicationDirectory", System.getenv("SOMTOOLBOX_BASEDIR"));
}
if (AbstractOptionFactory.getFilePath(config, "viewerWorkingDirectory") != null) {
viewerWorkingDirectoryName = AbstractOptionFactory.getFilePath(config, "viewerWorkingDirectory");
} else { // default the directory to the unit file location as the most likely path
viewerWorkingDirectoryName = FileUtils.getPathFrom(unitDescriptionFileName);
Logger.getLogger("at.tuwien.ifs.somtoolbox").info(
"Defaulting viewer working directory to " + viewerWorkingDirectoryName);
}
if (config.getString("fileNamePrefix") != null) {
CommonSOMViewerStateData.fileNamePrefix = config.getString("fileNamePrefix");
}
if (config.getString("fileNameSuffix") != null) {
CommonSOMViewerStateData.fileNameSuffix = config.getString("fileNameSuffix");
}
documentMode = config.getBoolean("documentMode", false);
/* load preferences from file */
String prefs_file = applicationDirectory + System.getProperty("file.separator") + PREFS_FILE;
try {
// first try properties file for specific operating system
String osname = System.getProperty("os.name").split(" ", 2)[0];
Logger.getLogger("at.tuwien.ifs.somtoolbox").info("Reading preferences from " + prefs_file + "." + osname);
prefs = new SOMViewerProperties(prefs_file + "." + osname);
} catch (PropertiesException e) {
try {
// then try to read generic properties file
Logger.getLogger("at.tuwien.ifs.somtoolbox").info("FAILED. Reading preferences from " + prefs_file);
prefs = new SOMViewerProperties(prefs_file);
} catch (PropertiesException pe) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(pe.getMessage());
// TODO show message
prefs = new SOMViewerProperties(); // create empty prefs to avoid NullPointerExceptions
}
}
// Load the users personal prefs-file (if it exists)
File userPrefs = SOMToolboxMetaConstants.USER_SOMVIEWER_PREFS;
if (userPrefs.exists() && userPrefs.canRead()) {
try {
prefs.load(new FileReader(userPrefs));
} catch (Exception e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").info(
"Could not load users preferences file: " + userPrefs.getPath());
}
}
CommonSOMViewerStateData.somViewerProperties = prefs;
if (prefs.getAudioPlayer() != null) {
CommonSOMViewerStateData.MimeTypes.setAudioPlayer(prefs.getAudioPlayer());
}
/** ** input objects *** */
state.inputDataObjects = new SharedSOMVisualisationData(classInformationFileName,
regressionInformationFileName, dataInformationFileName, dataWinnerMappingFileName, inputVectorFileName,
templateVectorFileName, linkageMapFileName);
// reading input objects, if we have filenames set
state.inputDataObjects.readAvailableData();
if (StringUtils.isNotBlank(inputCorrectionsFileName)) {
state.inputDataObjects.setFileName(SOMVisualisationData.INPUT_CORRECTIONS, inputCorrectionsFileName);
}
createAndShowGUI();
// if passed as parameter - set initial palette
String initialPalette = config.getString("initialPalette");
if (initialPalette != null) {
Palette palette = Palettes.getPaletteByName(initialPalette);
if (palette != null) {
// activate palette in menu
for (int i = 0; i < paletteMenu.getMenuComponentCount(); i++) {
if (paletteMenu.getMenuComponent(i) instanceof JRadioButtonMenuItem) {
JRadioButtonMenuItem rb = (JRadioButtonMenuItem) paletteMenu.getMenuComponent(i);
if (at.tuwien.ifs.somtoolbox.util.StringUtils.equalsAny(rb.getText(), palette.getName(),
palette.getShortName())) {
rb.setSelected(true);
break;
}
}
}
} else {
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning(
"Unknown initial palette '" + initialPalette + "'.");
}
}
// if passed as parameter - set initial visualisation
String initialVis = config.getString("initialVisualisation");
if (initialVis != null) {
BackgroundImageVisualizerInstance vis = Visualizations.getVisualizationByName(initialVis);
if (vis != null) {
initialVisualisation = vis.getVis();
initialVisualisationVariant = vis.getVariant();
try {
if (initialVisualisation instanceof AbstractMatrixVisualizer) {
((AbstractMatrixVisualizer) initialVisualisation).reversePalette();
}
// if passed as parameter - set initial visualisation params
String initialVisParams = config.getString("initialVisParams");
if (initialVisParams != null) {
// set params for SDH
if (initialVisualisation instanceof SmoothedDataHistograms) {
try {
int smoothingFactor = Integer.parseInt(initialVisParams);
SmoothedDataHistograms sdh = (SmoothedDataHistograms) initialVisualisation;
sdh.setSmoothingFactor(smoothingFactor);
SDHControlPanel controlPanel = (SDHControlPanel) sdh.getControlPanel();
controlPanel.spinnerSmoothingFactor.setValue(new Integer(smoothingFactor));
} catch (NumberFormatException e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning(
"Visualisation Param 'Smoothing factor' is not a number: '" + initialVisParams
+ "'.");
}
} else if (initialVisualisation instanceof ThematicClassMapVisualizer) {
ThematicClassMapVisualizer them = (ThematicClassMapVisualizer) initialVisualisation;
boolean voronoi = false;
boolean chessBoard = false;
double minVisibleClass = 0;
String[] params = initialVisParams.split(",");
for (String param : params) {
String[] property = param.split("=");
if (property == null || property.length != 2) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning(
"Visualisation property '" + property + "' is not correct in : '"
+ initialVisParams + "'.");
} else {
if (property[0].equalsIgnoreCase("voronoi")) {
voronoi = Boolean.valueOf(property[1]).booleanValue();
} else if (property[0].equalsIgnoreCase("chessboard")) {
chessBoard = Boolean.valueOf(property[1]).booleanValue();
} else if (property[0].equalsIgnoreCase("minVisibleClass")) {
minVisibleClass = Double.valueOf(property[1]).doubleValue();
}
}
}
System.out.println("params - chessBoard:" + chessBoard + ", voronoi:" + voronoi
+ ", minVisibleClass:" + minVisibleClass);
them.setInitialParams(chessBoard, voronoi, minVisibleClass);
} else if (initialVisualisation instanceof ComparisonVisualizer) {
ComparisonVisualizer compVis = (ComparisonVisualizer) initialVisualisation;
String[] soms = initialVisParams.split(",");
for (String string : soms) {
compVis.addSOM(string);
}
}
}
mapPane.setInitialVisualization(initialVisualisation, initialVisualisationVariant);
// select correct visualisation from menu
for (int i = 0; i < visualizationMenu.getMenuComponentCount(); i++) {
Component comp = visualizationMenu.getMenuComponent(i);
if (comp instanceof JRadioButtonMenuItem) {
JRadioButtonMenuItem radioButton = (JRadioButtonMenuItem) comp;
if (at.tuwien.ifs.somtoolbox.util.StringUtils.equalsAny(radioButton.getText(),
vis.getShortName(), vis.getName())) {
radioButton.setSelected(true);
}
}
}
updatePalettePanel();
visControlPanel.updateVisualisationControl();
resetControlElements(true);
} catch (SOMToolboxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning(
"Unknown initial visualisation '" + initialVis + "'.");
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning(
"Valid options are: " + Arrays.toString(Visualizations.getAvailableVisualizationNames()));
}
}
displayFrame(state.selectionPanel);
// if passed as parameter - set second SOM
if (StringUtils.isNotBlank(getMap().getState().secondSOMName)) {
updateSOMComparison(true);
mapPane.setShiftArrowsVisibility(true);
mapPane.centerAndFitMapToScreen(0);
}
}
private void createAndShowGUI() {
/** ** files given on command line are read in here, map is created *** */
mapPane = new SOMPane(this, weightVectorFileName, unitDescriptionFileName, mapDescriptionFileName, state);
// setTitle("PlaySOM");
setTitle("SOM Viewer - " + weightVectorFileName + " (version: " + SOMToolboxMetaConstants.getVersion() + ")");
try {
setIconImage(Toolkit.getDefaultToolkit().getImage(
ClassLoader.getSystemResource(RESOURCE_PATH_ICONS + "somviewer_logo-24.png")));
} catch (Exception e) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").info("Could not find application logo image file. Continuing.");
}
initWindowClosing();
state.fileChooser = new JFileChooser(new File(viewerWorkingDirectoryName + "/."));
/** ** MENU *** */
menuBar = new JMenuBar();
setJMenuBar(menuBar);
// begin file menu
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
menuBar.add(fileMenu);
JMenuItem dataFilesMenuItem = new JMenuItem("Data Files");
dataFilesMenuItem.setMnemonic(KeyEvent.VK_F);
dataFilesMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new SharedSOMVisualisationDataDialog(SOMViewer.this, state).setVisible(true);
}
});
fileMenu.add(dataFilesMenuItem);
// add the plot data menu entry
JMenuItem plotDataMenuItem;
if (state.inputDataObjects == null || state.inputDataObjects.getInputData() == null) {
plotDataMenuItem = new JMenuItem("Plot data (data needs to be loaded!)");
plotDataMenuItem.setEnabled(false);
} else if (state.inputDataObjects.getInputData().dim() > 3) {
plotDataMenuItem = new JMenuItem("Plot data (only for dim <= 3)");
plotDataMenuItem.setEnabled(false);
} else {
plotDataMenuItem = new JMenuItem("Plot data");
}
plotDataMenuItem.setMnemonic(KeyEvent.VK_P);
plotDataMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DataSetViewer viewer;
SOMLibClassInformation classInfo = state.inputDataObjects.getClassInfo();
InputData inputData = state.inputDataObjects.getInputData();
if (inputData == null) {
SOMVisualisationData inputObject = state.inputDataObjects.getObject(SOMVisualisationData.INPUT_VECTOR);
try {
inputObject.loadFromFile(state.fileChooser, SOMViewer.this);
inputData = state.inputDataObjects.getInputData();
} catch (SOMToolboxException e1) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe("Input data file needed!");
}
if (inputData == null) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe("Input data file needed!");
return;
}
}
if (classInfo == null) {
viewer = new DataSetViewer(SOMViewer.this, inputData.getData());
} else {
inputData.setClassInfo(classInfo);
String[] classNames = classInfo.classNames();
double[][][] data = new double[classNames.length][][];
for (int i = 0; i < classNames.length; i++) {
try {
data[i] = inputData.getData(classNames[i]);
} catch (SOMToolboxException ex) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(
"Error retrieving class info: " + ex.getMessage());
}
}
viewer = new DataSetViewer(SOMViewer.this, classNames, classLegendPane.getColors(), data);
}
viewer.setVisible(true);
}
});
fileMenu.add(plotDataMenuItem);
JMenuItem exitMenuItem = new JMenuItem("Exit");
exitMenuItem.setMnemonic(KeyEvent.VK_X);
exitMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
fileMenu.add(exitMenuItem);
// end file menu
menuBar.add(createMapMenu());
getContentPane().setLayout(new BorderLayout());
/** ** TOOLBar *** */
toolBar = new JToolBar("SOMViewer Toolbar");
toolBar.add(makeToolbarButton("center3d-24.png", CENTER_AND_FIT_MAP, "Center Map"));
toolBar.add(makeToolbarButton("reset-desktop.png", RESET_DESKTOP_LAYOUT, "Reset Layout"));
toolBar.addSeparator();
// Selection handler buttons
ArrayList<AbstractButton> selectionHandlerButtons = new ArrayList<AbstractButton>();
selectionHandlerButtons.add(makeToolbarToggleButton("rectangle.png", SELECT_RECTANGLE, "Rectangle Selection",
true));
selectionHandlerButtons.add(makeToolbarToggleButton("line.png", SELECT_LINE, "Line Selection", false));
selectionHandlerButtons.add(makeToolbarToggleButton("clusterSelection.png", SELECT_CLUSTER,
"Cluster Selection", false));
// rudi: moving inputs for semi-supervised learning
selectionHandlerButtons.add(makeToolbarToggleButton("moveinput.png", MOVE_INPUT, "Move Inputs", false));
// Angela: move Labels
selectionHandlerButtons.add(makeToolbarToggleButton("movelabel.png", MOVE_LABEL, "Move Labels", false));
ButtonGroup selectionHandlerButtonGroup = new ButtonGroup();
for (AbstractButton button : selectionHandlerButtons) {
toolBar.add(button);
selectionHandlerButtonGroup.add(button);
}
toolBar.addSeparator();
// end selection handler buttons
// toggles for map details (pie-charts, labels, data info
boolean classInfoLoaded = getMap().getInputObjects().getClassInfo() != null;
buttonPie.setIcon(TOGGLE_PIE_CHARTS_ICONS[0]);
buttonPie.setToolTipText("Toggle pie-chart display");
buttonPie.setEnabled(classInfoLoaded);
buttonPie.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
menuPie.show(buttonPie, 0, buttonPie.getHeight());
}
});
for (int i = 0; i < TOGGLE_PIE_CHARTS_MODES.length; i++) {
menuPie.add(makeButtonMenutEntry(TOGGLE_PIE_CHARTS_MODES[i], TOGGLE_PIE_CHARTS_ICONS[i]));
}
JMenuBar menuBarPieCharts = new JMenuBar();
menuBarPieCharts.setBorderPainted(false);
menuBarPieCharts.add(menuPie);
toolBar.add(buttonPie);
toolBar.add(makeToolbarToggleButton("labels.png", TOGGLE_LABELS, TOGGLE_LABELS, state.labelVisibilityMode));
toolBar.add(makeToolbarToggleButton("hits.png", TOGGLE_HITS, TOGGLE_HITS, state.hitsVisibilityMode));
toolBar.add(makeToolbarToggleButton("data.png", TOGGLE_DATA, TOGGLE_DATA, state.dataVisibilityMode));
boolean linkageInfoLoaded = getMap().getInputObjects().getLinkageMap() != null;
linkageToggleButton = makeToolbarToggleButton("linkage.png", TOGGLE_LINKAGE, "Linkage",
state.displayInputLinkage);
linkageToggleButton.setEnabled(linkageInfoLoaded);
toolBar.add(linkageToggleButton);
toolBar.addSeparator();
// toggles specific for input location (exact placement)
exactPlacementToggleButton = makeToolbarToggleButton("exactPlacement.png", TOGGLE_EXACT_PLACEMENT, "Exact",
state.exactUnitPlacement);
toolBar.add(exactPlacementToggleButton);
shiftOverlappingToggleButton = makeToolbarToggleButton("shiftOverlapping.png", TOGGLE_RELOCATE, "Relocate",
state.shiftOverlappingInputs);
toolBar.add(shiftOverlappingToggleButton);
if (!state.exactUnitPlacementEnabled) {
exactPlacementToggleButton.setEnabled(false);
exactPlacementToggleButton.setToolTipText(TOGGLE_EXACT_PLACEMENT + ": " + MSG_EXACTPLACEMENT_DISABLED);
shiftOverlappingToggleButton.setEnabled(false);
shiftOverlappingToggleButton.setToolTipText(TOGGLE_RELOCATE + ": " + MSG_EXACTPLACEMENT_DISABLED);
}
toolBar.addSeparator();
// end toggles for map details
toolBar.add(makeToolbarButton("createlabel.png", CREATE_LABEL, "New label"));
toolBar.addSeparator();
AbstractButton btn3dViewer = makeToolbarButton("somviewer3D_logo-24.png", SOMVIEWER_3D, "3D");
// Check if 3D is available
try {
Class.forName("at.tuwien.ifs.somtoolbox.apps.viewer3d.SOMViewer3D");
} catch (ClassNotFoundException e1) {
btn3dViewer.setEnabled(false);
}
toolBar.add(btn3dViewer);
toolBar.addSeparator();
getContentPane().add(toolBar, BorderLayout.PAGE_START);
/** ** StatusBar *** */
statusBar = new StatusBar();
getContentPane().add(statusBar, BorderLayout.PAGE_END);
if (loggingHandler != null) {
loggingHandler.setStatusBar(statusBar);
}
Logger.getLogger("at.tuwien.ifs.somtoolbox").info("Initializing GUI ...");
/** ** Layout of the left control pane *** */
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridx = 0;
collector = new ControlCollector("Test", state);
// desktop.add(collector, c);
/** ** Map Overview *** */
MapOverviewPane mapOverviewPane = new MapOverviewPane("Map overview", state);
mapOverviewPane.connect(mapPane.getCanvas(), new PLayer[] { mapPane.getCanvas().getLayer() });
collector.addControl(mapOverviewPane, true);
/** ** PlaySOMPanel *** */
AbstractSelectionPanel selectionPanel = makeSelectionPanel();
mapPane.connectSelectionHandlerTo(selectionPanel);
c.weighty = 0.5; // IMPORTANT note: these values remain active for ComparisonPanel
c.weightx = 0.1; // and are reset afterwards
// desktop.add(selectionPanel, c);
collector.addControl(selectionPanel, true);
state.selectionPanel = selectionPanel;
AbstractSelectionPanel diverPanel = null;
if (state.growingLayer.getAllSubMaps().size() > 0) {
// added by Philip Langer
/** ** HierarchicalDiverPanel *** */
diverPanel = new GHSOMNavigationPanel(state, mapPane);
mapPane.connectSelectionHandlerTo(diverPanel);
diverPanel.setVisible(true);
collector.addControl(diverPanel, true);
}
// /added by Philip Langer
/** ** Comparison *** */
ComparisonPanel compPanel = new ComparisonPanel(state);
mapPane.connectSelectionHandlerTo(compPanel);
collector.addControl(compPanel);
compPanel.setVisible(false);
c.weightx = 0.0;
c.weighty = 0.0;
MultichannelPlaybackPanel multichannelPlaybackPanel = new MultichannelPlaybackPanel(state, mapPane);
mapPane.connectSelectionHandlerTo(compPanel);
// desktop.add(mapPane, c);
// mapPane.setVisible(false);
c.weightx = 0.0;
c.weighty = 0.0;
/** ** Class legend panel *** */
classLegendPane = new ClassLegendPane(mapPane, "Class legend", state);
collector.addControl(classLegendPane, true);
/** ** Query legend panel *** */
queryPane = new QuerySOMPanel("Query", state);
collector.addControl(queryPane);
if (!documentMode) {
queryPane.setVisible(false);
}
/** ** Map detail panel *** */
MapDetailPanel mapDetailPanel = new MapDetailPanel("Map details", state);
mapDetailPanel.setVisible(false);
collector.addControl(mapDetailPanel);
// show the initial zoom factor
mapDetailPanel.updatePanel(mapPane.getCanvas().getCamera().getViewScale());
/** ** Shifts Control Panel *** */
shiftsControlPanel = new ShiftsControlPanel(mapPane, state, "Shifts Control Panel");
collector.addControl(shiftsControlPanel);
/** ** Palette panel *** */
palettePanel = new PalettePanel("Palette", state);
collector.addControl(palettePanel, true);
/** ** Visualization Control panel (e.g. SDH) *** */
visControlPanel = new VisualizationControl("Visualisation control", state, mapPane); // just a placeholder for
// the actual control panel
collector.addControl(visControlPanel, true);
// desktop.add(visControlPanel, c);
/** ** Clustering Control panel (Angela) *** */
clusteringControl = new ClusteringControl("Clustering Control", state, mapPane);
clusteringControl.setVisible(false);
collector.addControl(clusteringControl);
/* PocketSOM Conncetor (Jakob) */
PocketSOMConnector psCon = new PocketSOMConnector("PocketSOM Connector", state);
psCon.setVisible(false);
collector.addControl(psCon);
/* */
PlaygroundPanel pgp = new PlaygroundPanel("Playground", state);
pgp.setVisible(false);
collector.addControl(pgp);
somFrame.getContentPane().add(mapPane);
somFrame.toBack();
// desktop.add(somFrame);
JSplitPane central = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, collector, mapPane);
central.setOneTouchExpandable(true);
getContentPane().add(central, BorderLayout.CENTER);
// getContentPane().add(desktop, BorderLayout.CENTER);
// collector.pack();
collector.setVisible(true);
createVisualizationMenu();
menuBar.add(visualizationMenu);
/** ** palette menu *** */
menuBar.add(createPaletteMenu());
// Angela: add the cluster menu
createClusterMenu();
// add the export menu
createExportMenu();
// add the input correction menu
JMenu inputCorrectionMenu = new JMenu("Input correction");
JMenuItem loadInputCorrectionsFileMenuItem = new JMenuItem("Load corrections file");
loadInputCorrectionsFileMenuItem.setMnemonic(KeyEvent.VK_L);
loadInputCorrectionsFileMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File inputFile = ExportUtils.getFilePath(SOMViewer.this, state.fileChooser,
"Load input corrections file", new FileNameExtensionFilter("Input corrections file (*.cor)",
"corr"));
if (inputFile != null) {
try {
state.inputDataObjects.getInputCorrections().readFromFile(inputFile.getAbsolutePath(),
state.growingLayer, state.inputDataObjects.getInputData());
getMap().createInputCorrectionArrows();
getMap().updateDetailsAfterMoving();
JOptionPane.showMessageDialog(SOMViewer.this, "Loading input corrections from file '"
+ inputFile.getAbsolutePath() + "' finished!");
} catch (SOMToolboxException ex) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(ex.getMessage());
}
}
}
});
inputCorrectionMenu.add(loadInputCorrectionsFileMenuItem);
JMenuItem saveInputCorrectionsFileMenuItem = new JMenuItem("Save corrections file");
saveInputCorrectionsFileMenuItem.setMnemonic(KeyEvent.VK_S);
saveInputCorrectionsFileMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File outputFile = ExportUtils.getFilePath(SOMViewer.this, state.fileChooser,
"Save input corrections file", new FileNameExtensionFilter("Input corrections file (*.corr)",
"corr"));
if (outputFile != null) {
try {
String outputFileName = outputFile.getAbsolutePath();
if (!outputFileName.endsWith(".corr")) {
outputFileName += ".corr";
outputFile = new File(outputFileName);
}
state.inputDataObjects.getInputCorrections().writeToFile(outputFile);
JOptionPane.showMessageDialog(SOMViewer.this, "Saving input corrections to file '"
+ outputFile.getAbsolutePath() + "' finished!");
} catch (SOMToolboxException ex) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(ex.getMessage());
}
}
}
});
inputCorrectionMenu.add(saveInputCorrectionsFileMenuItem);
JMenuItem saveUnitFileMenuItem = new JMenuItem("Save moved unit file");
saveUnitFileMenuItem.setMnemonic(KeyEvent.VK_U);
saveUnitFileMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File outputFile = ExportUtils.getFilePath(SOMViewer.this, state.fileChooser, "Save unit file",
new FileNameExtensionFilter("Unit description files (*.unit)", "unit"));
if (outputFile != null) {
try {
SOMLibMapOutputter.writeUnitDescriptionFile(state.growingSOM,
outputFile.getParentFile().getAbsolutePath(), outputFile.getName(), true);
JOptionPane.showMessageDialog(SOMViewer.this, "Saving to unit file '"
+ outputFile.getAbsolutePath() + "' finished!");
} catch (IOException ex) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(
"Error writing unit file: " + ex.getMessage());
}
}
}
});
inputCorrectionMenu.add(saveUnitFileMenuItem);
JMenuItem clearInputCorrectionsMenuItem = new JMenuItem("Clear corrections");
clearInputCorrectionsMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (InputCorrection correction : state.inputDataObjects.getInputCorrections().getInputCorrections()) {
correction.getSourceUnit().addMappedInput(correction.getLabel(), correction.getOriginalDistance(),
true);
correction.getTargetUnit().removeMappedInput(correction.getLabel());
}
getMap().updateDetailsAfterMoving();
state.inputDataObjects.getInputCorrections().getInputCorrections().clear();
getMap().clearInputCorrections();
}
});
inputCorrectionMenu.add(clearInputCorrectionsMenuItem);
final JCheckBoxMenuItem showInputCorrectionsMenuItem = new JCheckBoxMenuItem("Show corrections");
showInputCorrectionsMenuItem.setSelected(true);
showInputCorrectionsMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getMap().setInputCorrectionsVisible(showInputCorrectionsMenuItem.isSelected());
}
});
inputCorrectionMenu.add(showInputCorrectionsMenuItem);
JMenu calcFeatureWeightsMenu = new JMenu("Calculate feature weights");
JMenuItem calcFeatureWeightsGlobalMenuItem = new JMenuItem("Global");
calcFeatureWeightsGlobalMenuItem.addActionListener(new CalculateFeatureWeightsActionListener(
FeatureWeightMode.GLOBAL));
calcFeatureWeightsMenu.add(calcFeatureWeightsGlobalMenuItem);
JMenuItem calcFeatureWeightsLocalMenuItem = new JMenuItem("Local");
calcFeatureWeightsLocalMenuItem.addActionListener(new CalculateFeatureWeightsActionListener(
FeatureWeightMode.LOCAL));
calcFeatureWeightsMenu.add(calcFeatureWeightsLocalMenuItem);
JMenuItem calcFeatureWeightsGeneralMenuItem = new JMenuItem("General");
calcFeatureWeightsGeneralMenuItem.addActionListener(new CalculateFeatureWeightsActionListener(
FeatureWeightMode.GENERAL));
calcFeatureWeightsMenu.add(calcFeatureWeightsGeneralMenuItem);
inputCorrectionMenu.add(calcFeatureWeightsMenu);
menuBar.add(inputCorrectionMenu);
// end mapCorrectionMenu
// add the labelling menu
JMenu labelMenu = new JMenu("Labelling");
JMenuItem runLabelMenuItem = new JMenuItem("Rerun labelling");
runLabelMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new LabellingDialog(state).setVisible(true);
}
});
labelMenu.add(runLabelMenuItem);
menuBar.add(labelMenu);
// window menu
state.registerComponentWindow(toolBar, "Toolbar");
state.registerComponentWindow(somFrame, "SOM Map");
// controls, ordered in their appearance
state.registerComponentWindow(mapOverviewPane, "Map Overview");
state.registerComponentWindow(selectionPanel, "Play Selection");
if (diverPanel != null) {
// added by Philip Langer
state.registerComponentWindow(diverPanel, "Hierarchical Diver Control");
// /added by Philip Langer
}
state.registerComponentWindow(classLegendPane, "Class Legend");
state.registerComponentWindow(shiftsControlPanel, "Shifts Control");
state.registerComponentWindow(palettePanel, "Palette");
state.registerComponentWindow(compPanel, "Label Comparison");
state.registerComponentWindow(queryPane, "Map Query");
state.registerComponentWindow(visControlPanel, "Visualization Control");
state.registerComponentWindow(clusteringControl, "Clustering Control");
state.registerComponentWindow(mapDetailPanel, "Map Detail Control");
state.registerComponentWindow(psCon, "PocketSOM Connector");
state.registerComponentWindow(pgp, "Playground");
state.registerComponentWindow(multichannelPlaybackPanel, "Multichannel playback panel");
// register observers to the class information
getMap().getInputObjects().getObject(SOMVisualisationData.CLASS_INFO).addObserver(this);
pack();
somFrame.pack();
somFrame.setLocation(state.controlElementsWidth, 0);
somFrame.setVisible(true);
toolBar.add(Box.createHorizontalGlue());
AbstractButton btnDonate = makeToolbarButton("donate.png", "Make a donation", "Donate!");
btnDonate.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
java.awt.Desktop.getDesktop().browse(new URI("http://www.ifs.tuwien.ac.at/dm/somtoolbox/"));
} catch (Exception ex) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning("Could not launch external browser.");
}
}
});
toolBar.add(btnDonate);
createWindowMenu(mapOverviewPane);
}
private int rotatedQuadrants = 0;
private boolean flippedX = false, flippedY = false;
private void doAnimation() {
// Set to 0 to deactivate animation.
int animationDuration = 1500;
int delta = 1000;
Random rand = new Random();
for (Unit u : state.growingLayer.getAllUnits()) {
GeneralUnitPNode unit = state.mapPNode.getUnit(u);
AffineTransform transform = AffineTransform.getQuadrantRotateInstance(-rotatedQuadrants, unit.getX()
+ unit.getWidth() / 2, unit.getY() + unit.getHeight() / 2);
if (flippedX) {
if (rotatedQuadrants % 2 == 0) {
transform.scale(-1, 1);
transform.translate(-(2 * unit.getX() + unit.getHeight()), 0);
} else {
transform.scale(1, -1);
transform.translate(0, -(2 * unit.getY() + unit.getWidth()));
}
}
if (flippedY) {
if (rotatedQuadrants % 2 == 0) {
transform.scale(1, -1);
transform.translate(0, -(2 * unit.getY() + unit.getWidth()));
} else {
transform.scale(-1, 1);
transform.translate(-(2 * unit.getX() + unit.getHeight()), 0);
}
}
unit.animateToTransform(transform, animationDuration
+ (animationDuration > 0 ? rand.nextInt(delta) - delta / 2 : 0));
}
AffineTransform transform = AffineTransform.getQuadrantRotateInstance(rotatedQuadrants,
state.mapPNode.getWidth() / 2, state.mapPNode.getHeight() / 2);
if (flippedX) {
transform.scale(-1, 1);
transform.translate(-state.mapPNode.getWidth(), 0);
}
if (flippedY) {
transform.scale(1, -1);
transform.translate(0, -state.mapPNode.getHeight());
}
mapPane.node.animateToTransform(transform, animationDuration);
mapPane.lineSelection.animateToTransform(transform, animationDuration);
}
/**
* @return The Map Menu
*/
private JMenu createMapMenu() {
JMenu mapMenu = new JMenu("Map");
mapMenu.setMnemonic('M');
JMenuItem rotCW = makeButtonMenutEntry("Rotate Clockwise", "map_rotate+90.png", 'R', KeyStroke.getKeyStroke(
KeyEvent.VK_R, InputEvent.ALT_DOWN_MASK));
rotCW.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
rotatedQuadrants = (rotatedQuadrants + 1) % 4;
doAnimation();
}
});
JMenuItem rotCCW = makeButtonMenutEntry("Rotate CounterClockwise", "map_rotate-90.png", 'C',
KeyStroke.getKeyStroke("alt pressed L"));
rotCCW.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
rotatedQuadrants = (rotatedQuadrants + 3) % 4;
doAnimation();
}
});
JMenuItem flipH = makeButtonMenutEntry("Flip around horizontal axis", "map_flip_h.png", 'H',
KeyStroke.getKeyStroke("alt pressed H"));
flipH.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (rotatedQuadrants % 2 == 0) {
flippedY = !flippedY;
} else {
flippedX = !flippedX;
}
doAnimation();
}
});
JMenuItem flipV = makeButtonMenutEntry("Flip around vertical axis", "map_flip_v.png", 'V',
KeyStroke.getKeyStroke("alt pressed V"));
flipV.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (rotatedQuadrants % 2 == 0) {
flippedX = !flippedX;
} else {
flippedY = !flippedY;
}
doAnimation();
}
});
JMenuItem save = makeButtonMenutEntry("Save Map", "map_save.png");
save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
JCheckBox chkGZIP = new JCheckBox("GZip compress");
chkGZIP.setSelected(true);
JPanel accessory = new JPanel();
accessory.add(chkGZIP);
state.fileChooser.setAccessory(accessory);
final int result = state.fileChooser.showSaveDialog(SOMViewer.this);
state.fileChooser.setAccessory(null);
if (result != JFileChooser.APPROVE_OPTION) {
return;
}
File target = state.fileChooser.getSelectedFile();
String dir = target.getParent();
String output = target.getName();
GrowingSOM newSOM = (GrowingSOM) state.growingSOM.clone();
if (flippedX) {
newSOM.getLayer().flip(Flip.VERTICAL);
}
if (flippedY) {
newSOM.getLayer().flip(Flip.HORIZONTAL);
}
switch (rotatedQuadrants) {
case 1:
newSOM.getLayer().rotate(Rotation.ROTATE_90);
break;
case 2:
newSOM.getLayer().rotate(Rotation.ROTATE_180);
break;
case 3:
newSOM.getLayer().rotate(Rotation.ROTATE_270);
break;
default:
// nop;
}
SOMLibMapOutputter.writeUnitDescriptionFile(newSOM, dir, output, chkGZIP.isSelected());
SOMLibMapOutputter.writeWeightVectorFile(newSOM, dir, output, chkGZIP.isSelected());
if (state.growingSOM.getSharedInputObjects().getObject(SOMVisualisationData.DATA_WINNER_MAPPING) != null) {
SOMLibDataWinnerMapping dwm = state.growingSOM.getSharedInputObjects().getDataWinnerMapping().clone();
if (flippedX) {
dwm.flipV(state.growingLayer.getXSize());
}
if (flippedY) {
dwm.flipH(state.growingLayer.getYSize());
}
dwm.rotate(rotatedQuadrants, state.growingLayer.getXSize(), state.growingLayer.getYSize());
SOMLibMapOutputter.writeDataWinnerMappingFile(dwm, dir, output, chkGZIP.isSelected());
}
} catch (CloneNotSupportedException e1) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe("Could not copy the map");
e1.printStackTrace();
} catch (IOException e2) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe("Could not save the changed map");
e2.printStackTrace();
}
}
});
mapMenu.add(rotCW);
mapMenu.add(rotCCW);
mapMenu.addSeparator();
mapMenu.add(flipH);
mapMenu.add(flipV);
mapMenu.addSeparator();
mapMenu.add(save);
return mapMenu;
}
private JMenuItem makeButtonMenutEntry(final String text, final String imageName, final char mnemonic,
final KeyStroke shortCut) {
return makeButtonMenutEntry(text, imageName, ((int) mnemonic), shortCut);
}
private JMenuItem makeButtonMenutEntry(final String text, final String imageName, final int mnemonic) {
return makeButtonMenutEntry(text, imageName, mnemonic, null);
}
private JMenuItem makeButtonMenutEntry(final String text, final String imageName) {
return makeButtonMenutEntry(text, imageName, -1);
}
private JMenuItem makeButtonMenutEntry(final String text, final String imageName, final int mnemonic,
final KeyStroke shortCut) {
JMenuItem menuItem = makeButtonMenutEntry(text, UiUtils.getIcon(imageName));
if (mnemonic > 0) {
menuItem.setMnemonic(mnemonic);
}
if (shortCut != null) {
menuItem.setAccelerator(shortCut);
}
return menuItem;
}
private JMenuItem makeButtonMenutEntry(final String text, final ImageIcon icon) {
JMenuItem jMenuItem = new JMenuItem(text, icon);
jMenuItem.addActionListener(this);
return jMenuItem;
}
private void displayFrame(AbstractSelectionPanel selectionPanel) {
resetControlElements(false);
mapPane.centerAndFitMapToScreen(0);
if (documentMode) {
initDocViewer(selectionPanel);
}
if (classColoursFile != null && state.inputDataObjects.getClassInfo() != null) {
state.inputDataObjects.getClassInfo().loadClassColours(new File(classColoursFile));
classLegendPane.updateClassColours();
}
setVisible(true);
}
private JMenu createPaletteMenu() {
if (paletteMenu == null) {
paletteMenu = new JMenu("Palette");
paletteMenu.setMnemonic(KeyEvent.VK_P);
rebuildPaletteMenu();
}
return paletteMenu;
}
public void rebuildPaletteMenu() {
final int MIN_SUBMENU_SIZE = 3;
paletteMenu.removeAll();
paletteMenuItemGroup = new ButtonGroup();
// List available palettes
Hashtable<String, ArrayList<Palette>> plist = new Hashtable<String, ArrayList<Palette>>();
Palette[] availablePalettes = Palettes.getAvailablePalettes();
for (Palette palette : availablePalettes) {
if (palette.isHidden()) {
continue;
}
ArrayList<Palette> sub = plist.get(palette.getPaletteGroup());
if (sub == null) {
sub = new ArrayList<Palette>();
}
sub.add(palette);
plist.put(palette.getPaletteGroup(), sub);
}
TreeSet<String> groups = new TreeSet<String>();
groups.addAll(plist.keySet());
for (String group : groups) {
if (group.length() == 0) {
// The default group is handled separately.
continue;
}
ArrayList<Palette> pl = plist.get(group);
JMenu currentM;
if (pl.size() < 1) {
// Ignore empty groups
continue;
} else if (pl.size() < MIN_SUBMENU_SIZE) {
// Flat
currentM = paletteMenu;
} else {
// SubMenu
currentM = new JMenu(group);
paletteMenu.add(currentM);
}
for (Palette palette : pl) {
JRadioButtonMenuItem paletteMenuItem = new JRadioButtonMenuItem(palette.getName());
paletteMenuItem.setMnemonic(palette.getName().charAt(0));
paletteMenuItem.setActionCommand(palette.getName());
paletteMenuItemGroup.add(paletteMenuItem);
paletteMenuItem.addActionListener(new PaletteCheckboxMenuItemListener(palette));
paletteMenuItem.setToolTipText(palette.getDescription());
if (palette == Palettes.getDefaultPalette()) {
paletteMenuItem.setSelected(true);
}
currentM.add(paletteMenuItem);
}
}
// The default group
if (paletteMenu.getComponentCount() > 0) {
paletteMenu.addSeparator();
}
if (plist.get("") != null) {
for (Palette palette : plist.get("")) {
JRadioButtonMenuItem paletteMenuItem = new JRadioButtonMenuItem(palette.getName());
paletteMenuItem.setMnemonic(palette.getName().charAt(0));
paletteMenuItemGroup.add(paletteMenuItem);
paletteMenuItem.addActionListener(new PaletteCheckboxMenuItemListener(palette));
paletteMenuItem.setToolTipText(palette.getDescription());
if (palette == Palettes.getDefaultPalette()) {
paletteMenuItem.setSelected(true);
}
paletteMenu.add(paletteMenuItem);
}
}
// Other Stuff
paletteMenu.addSeparator();
if (reversePaletteMenuItem == null) {
reversePaletteMenuItem = new JCheckBoxMenuItem("Reverse");
reversePaletteMenuItem.setMnemonic(KeyEvent.VK_R);
reversePaletteMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
boolean success = getMap().reversePalette();
if (success) {
SOMViewer.this.visualizationChangeSuccess();
} else {
SOMViewer.this.visualizationChangeFailure();
}
updatePalettePanel();
mapPane.repaint();
} catch (SOMToolboxException ex) {
JOptionPane.showMessageDialog(SOMViewer.this, ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
}
});
}
paletteMenu.add(reversePaletteMenuItem);
paletteMenu.addSeparator();
JMenuItem importer = new JMenuItem("Import Palette File");
importer.setMnemonic(KeyEvent.VK_I);
importer.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser jfc = state.getFileChooser();
jfc.setFileFilter(new FileFilter() {
@Override
public String getDescription() {
return "XML Palette Files";
}
@Override
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
if (f.getName().endsWith(".xml")) {
return true;
}
return false;
}
});
if (jfc.showOpenDialog(SOMViewer.this) == JFileChooser.APPROVE_OPTION) {
try {
Palettes.addPalette(Palette.loadPaletteFromXML(jfc.getSelectedFile()));
rebuildPaletteMenu();
} catch (SOMToolboxException e1) {
JOptionPane.showMessageDialog(SOMViewer.this, e1.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
}
}
});
paletteMenu.add(importer);
paletteMenu.addSeparator();
if (paletteEditorMenuItem == null) {
paletteEditorMenuItem = new JMenuItem("Palette Editor");
paletteEditorMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new PaletteEditor(SOMViewer.this, state).setVisible(true);
}
});
}
paletteMenu.add(paletteEditorMenuItem);
}
private void resetControlElements(boolean maximizeElements) {
for (AbstractViewerControl avc : collector.getDefaultControls()) {
if (avc.isFullFunctional()) {
avc.setVisible(true);
}
}
for (int i = 0; i < state.registeredViewerControls.size(); i++) {
AbstractViewerControl comp = (AbstractViewerControl) state.registeredViewerControls.get(i);
if (comp.isVisible()) {
if (maximizeElements) {
comp.setCollapsed(false);
}
}
}
}
private void resetDesktopLayout() {
resetControlElements(true);
}
private AbstractSelectionPanel makeSelectionPanel() {
if (documentMode) {
return new DocSOMPanel(state);
} else {
if (noInternalPlayer) {
return new PlaySOMPanel(state);
} else {
return new PlaySOMPlayer(state);
}
}
}
private void createWindowMenu(MapOverviewPane mapOverviewPane) {
windowMenu = new JMenu("Window");
windowMenu.setMnemonic(KeyEvent.VK_W);
ArrayList<String> componentNames = new ArrayList<String>(state.registeredComponentWindows.keySet());
Collections.sort(componentNames);
for (String name : componentNames) {
Component component = state.registeredComponentWindows.get(name);
MyJCheckBoxMenuItem checkBoxMenuItem = new MyJCheckBoxMenuItem(name, component);
windowMenu.add(checkBoxMenuItem);
}
menuBar.add(windowMenu);
}
public void uncheckComponentInMenu(Component comp) {
if (windowMenu == null) {
return;
}
Component[] components = windowMenu.getMenuComponents();
for (Component component2 : components) {
if (component2 instanceof MyJCheckBoxMenuItem) {
MyJCheckBoxMenuItem item = (MyJCheckBoxMenuItem) component2;
if (item.getComponent() == comp) {
item.setSelected(false);
}
}
}
}
private void createVisualizationMenu() {
visualizationMenu = new JMenu("Visualization");
visualizationMenu.setMnemonic(KeyEvent.VK_V);
visualizationMenuItemGroup = new ButtonGroup();
JRadioButtonMenuItem nonVis = new JRadioButtonMenuItem("none");
nonVis.setToolTipText("no cluster visualization");
nonVis.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
mapPane.setNoVisualization();
palettePanel.setPalette(null);
visControlPanel.updateVisualisationControl();
}
});
visualizationMenuItemGroup.add(nonVis);
visualizationMenu.add(nonVis);
BackgroundImageVisualizer[] visualisations = Visualizations.getAvailableVisualizations();
JMenu currentVisMenu = new JMenu("Visualisations");
visualizationMenu.add(currentVisMenu);
boolean firstQualityMeasure = false;
boolean firstCompareVis = false;
for (int v = 0; v < visualisations.length; v++) {
if (visualisations[v] instanceof ComparisonVisualizer && !firstCompareVis) {
currentVisMenu.remove(currentVisMenu.getItemCount() - 1);
currentVisMenu = new JMenu("SOM Comparison");
visualizationMenu.add(currentVisMenu);
firstCompareVis = true;
} else if (visualisations[v] instanceof QualityMeasureVisualizer && !firstQualityMeasure) {
currentVisMenu.remove(currentVisMenu.getItemCount() - 1);
currentVisMenu = new JMenu("Quality Measures");
visualizationMenu.add(currentVisMenu);
firstQualityMeasure = true;
}
for (int w = 0; w < visualisations[v].getNumberOfVisualizations(); w++) {
JMultiLineRadioButtonMenuItem mi = new JMultiLineRadioButtonMenuItem(
visualisations[v].getVisualizationName(w));
mi.addActionListener(new VisualizationActionListener(v, w));
mi.setToolTipText(visualisations[v].getVisualizationDescription(w));
visualizationMenuItemGroup.add(mi);
currentVisMenu.add(mi);
if (visualisations[v] instanceof ThematicClassMapVisualizer) {
thematicClassRadioButton = mi;
if (!((ThematicClassMapVisualizer) visualisations[v]).hasClassInfo()) {
mi.setEnabled(false);
}
}
}
currentVisMenu.add(new JSeparator());
}
currentVisMenu.remove(currentVisMenu.getItemCount() - 1);
nonVis.setSelected(true);
oldSelectedVisualizationMenuItem = nonVis.getModel();
JMenuItem clearVisCacheMenuItem = new JMenuItem("Clear Visualisation Cache");
clearVisCacheMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// clear the visualisation cache
AbstractBackgroundImageVisualizer.clearVisualisationCache();
}
});
visualizationMenu.add(clearVisCacheMenuItem);
visualizationMenu.add(new JSeparator());
final JCheckBoxMenuItem showBackgroundImageMenuItem = new JCheckBoxMenuItem("Show background image");
showBackgroundImageMenuItem.setMnemonic(KeyEvent.VK_B);
showBackgroundImageMenuItem.setEnabled(false);
showBackgroundImageMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getMap().setBackgroundImageVisibility(showBackgroundImageMenuItem.isSelected());
mapPane.getCurrentVisualization().getControlPanel().updateSwitchControls();
}
});
visualizationMenu.add(showBackgroundImageMenuItem);
JMenuItem loadBackgroundImageMenuItem = new JMenuItem("Load background image");
loadBackgroundImageMenuItem.setMnemonic(KeyEvent.VK_L);
loadBackgroundImageMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = state.fileChooser;
if (fileChooser.getSelectedFile() != null) { // reusing the dialog
state.fileChooser = new JFileChooser(fileChooser.getSelectedFile().getPath());
}
fileChooser.setName("Open Background Image");
int returnVal = fileChooser.showDialog(SOMViewer.this, "Open Image");
if (returnVal == JFileChooser.APPROVE_OPTION) {
try {
BufferedImage image = ImageIO.read(new File(fileChooser.getSelectedFile().getAbsolutePath()));
getMap().setBackgroundImage(image);
showBackgroundImageMenuItem.setEnabled(true);
showBackgroundImageMenuItem.setSelected(true);
if (mapPane.getCurrentVisualization() != null
&& mapPane.getCurrentVisualization().getControlPanel() != null) {
mapPane.getCurrentVisualization().getControlPanel().updateSwitchControls();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
visualizationMenu.add(loadBackgroundImageMenuItem);
showShiftsMenuItem = new JCheckBoxMenuItem("Show data shifts");
showShiftsMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
mapPane.setShiftArrowsVisibility(showShiftsMenuItem.isSelected());
shiftsControlPanel.setEnabled(showShiftsMenuItem.isSelected());
}
});
if (getMap().getState().secondSOMName.equals("")) {
showShiftsMenuItem.setEnabled(false);
shiftsControlPanel.setVisible(false);
} else {
showShiftsMenuItem.setSelected(true);
shiftsControlPanel.setVisible(true);
}
visualizationMenu.add(showShiftsMenuItem);
// switch map submenu
switchMapSubmenu = new JMenu("Switch map");
switchMapSubmenu.setToolTipText("Switch visualisations between main and second map.");
useMainMap = new JMultiLineRadioButtonMenuItem("Use main map");
useMainMap.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// add magic here.
// mapPane.setShiftsVisibility(showShiftsMenuItem.isSelected());
// shiftsControlPanel.setEnabled(showShiftsMenuItem.isSelected());
// mapPane.updateShifts();
}
});
useSecondMap = new JMultiLineRadioButtonMenuItem("Use second map");
useSecondMap.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// add magic here.
// mapPane.setShiftsVisibility(showShiftsMenuItem.isSelected());
// shiftsControlPanel.setEnabled(showShiftsMenuItem.isSelected());
// mapPane.updateShifts();
}
});
ButtonGroup switchMapMenuGroup = new ButtonGroup();
switchMapMenuGroup.add(useMainMap);
switchMapMenuGroup.add(useSecondMap);
switchMapSubmenu.add(useMainMap);
switchMapSubmenu.add(useSecondMap);
if (getMap().getState().secondSOMName.equals("")) {
switchMapSubmenu.setEnabled(false);
} else {
switchMapSubmenu.setSelected(true);
}
visualizationMenu.add(switchMapSubmenu);
Logger.getLogger("at.tuwien.ifs.somtoolbox").info("SOMViewer ready.");
}
/**
* creates a menu entry for exporting the current visualization
*/
private void createExportMenu() {
JMenu exportMenu = new JMenu("Export");
exportMenu.setMnemonic(KeyEvent.VK_X);
JMenuItem exportMapPane = new JMenuItem("Export current MapPane ...");
exportMapPane.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ExportUtils.saveMapPaneAsImage(SOMViewer.this, SOMViewer.this.state.getFileChooser(), mapPane,
"Save MapPane as PNG");
}
});
JMenuItem exportVisualization = new JMenuItem("Export current Visualization ...");
exportVisualization.setMnemonic(KeyEvent.VK_X);
exportVisualization.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File filePath = ExportUtils.getFilePath(SOMViewer.this, SOMViewer.this.state.getFileChooser(),
"Save Visualization as PNG");
if (filePath != null) {
try {
ExportUtils.saveVisualizationAsImage(SOMViewer.this.state, -1, filePath.getAbsolutePath());
JOptionPane.showMessageDialog(SOMViewer.this, "Export to file finished!");
} catch (SOMToolboxException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(getParent(), ex.getMessage(), "Error saving",
JOptionPane.ERROR_MESSAGE);
}
}
}
});
JMenuItem exportToPocketSOMFormat = new JMenuItem("Export to PocketSOMFormat ...");
exportToPocketSOMFormat.setMnemonic(KeyEvent.VK_P);
exportToPocketSOMFormat.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File outputFile = ExportUtils.getFilePath(SOMViewer.this, state.fileChooser, "Save in PocketSOMFormat");
if (outputFile != null) {
PocketSOMFormatUtils.convertMapFormat(state.growingLayer, outputFile.getAbsolutePath());
JOptionPane.showMessageDialog(SOMViewer.this, "Export to PocketSOMFormat finished!");
}
}
});
JMenuItem exportRhythmPatterns = new JMenuItem("Export Rhythm Patterns Images ...");
exportRhythmPatterns.setMnemonic(KeyEvent.VK_R);
exportRhythmPatterns.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File outputFile = ExportUtils.getFilePath(SOMViewer.this, state.fileChooser,
"Export Rhythm Patterns Images");
if (outputFile != null) {
try {
ExportUtils.saveRhythmPatternsOfWeightVectors(outputFile.getAbsolutePath(), state.growingLayer);
JOptionPane.showMessageDialog(SOMViewer.this, "Export of Rhythm Patterns Images finished!");
} catch (SOMToolboxException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(getParent(), ex.getMessage(),
"Error exporting Rhythm Patterns Images!", JOptionPane.ERROR_MESSAGE);
}
}
}
});
JMenuItem exportVisualizationAdvanced = new JMenuItem("Export as HTML ...");
exportVisualizationAdvanced.setMnemonic(KeyEvent.VK_X);
exportVisualizationAdvanced.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new ExportDialog(SOMViewer.this, state).setVisible(true);
}
});
JMenuItem exportTuxRacer = new JMenuItem("Export TuxRacer Map...");
exportTuxRacer.setMnemonic(KeyEvent.VK_T);
exportTuxRacer.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new TuxRacerExportDialog(SOMViewer.this, state).setVisible(true);
}
});
// ADDED: SEBASTIAN SKRITEK -
JMenuItem exportReport = new JMenuItem("Create Report ... ");
exportReport.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new ReportGenerator(false, state);
}
});
exportMenu.add(exportMapPane);
exportMenu.add(exportVisualization);
exportMenu.add(exportVisualizationAdvanced);
exportMenu.add(exportRhythmPatterns);
exportMenu.add(exportToPocketSOMFormat);
exportMenu.add(exportTuxRacer);
exportMenu.add(exportReport);
menuBar.add(exportMenu);
}
private class CalculateFeatureWeightsActionListener implements ActionListener {
private FeatureWeightMode mode;
public CalculateFeatureWeightsActionListener(FeatureWeightMode mode) {
this.mode = mode;
}
@Override
public void actionPerformed(ActionEvent e) {
try {
InputCorrections calculatedCorrections = getMap().getGsom().getLayer().computeUnitFeatureWeights(
state.inputDataObjects.getInputCorrections(), state.inputDataObjects.getInputData(), mode);
// remove potentially existing nodes
getMap().clearInputCorrections(CreationType.COMPUTED);
for (InputCorrection correction : calculatedCorrections.getInputCorrections()) {
ArrowPNode arrow = ArrowPNode.createInputCorrectionArrow(correction,
InputCorrections.CreationType.COMPUTED, getMap().getUnit(correction.getSourceUnit()),
getMap().getUnit(correction.getTargetUnit()));
getMap().getInputCorrectionsPNode().addChild(arrow);
arrow.moveToBack();
}
} catch (SOMToolboxException ex) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(ex.getMessage());
}
}
}
private class ClusteringMenuItemActionListener implements ActionListener {
private TreeBuilder builder;
public ClusteringMenuItemActionListener(TreeBuilder builder) {
this.builder = builder;
}
@Override
public void actionPerformed(ActionEvent e) {
SwingWorker worker = new TreeBuildWorker();
worker.start();
}
// builds the tree in a separate thread and shows progress bar
private class TreeBuildWorker extends SwingWorker {
private ProgressMonitor monitor;
public TreeBuildWorker() {
monitor = new ProgressMonitor(SOMViewer.this, "Building cluster tree...", "", 0, 100); // Maximum will
// be set later;
}
@Override
public Object construct() {
if (builder != null) {
builder.setMonitor(monitor);
}
try {
getMap().buildTree(builder);
showPalettePanel();
redrawClustering();
// also show clustering control element
clusteringControl.updateControlDisplay();
clusteringControl.setVisible(true);
} catch (ClusteringAbortedException ex) {
// reset to old menu item
SOMViewer.this.clusterMethodGroup.setSelected(previousSelectedClusteringMethod, true);
} catch (Exception ex) {
ex.printStackTrace();
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(
"Error during Clustering: " + ex.getClass().getSimpleName() + ": " + ex.getMessage());
// reset to old menu item
SOMViewer.this.clusterMethodGroup.setSelected(previousSelectedClusteringMethod, true);
}
previousSelectedClusteringMethod = SOMViewer.this.clusterMethodGroup.getSelection();
monitor.close();
return null;
}
}
}
// Angela
private void redrawClustering() {
// BasicStroke bs = new BasicStroke(12.0f);
getMap().showClusters(this.clusteringLevel, false);
}
private MapPNode getMap() {
return mapPane.getMap();
}
// Angela: creates a menu entry for showing clusters
private void createClusterMenu() {
JMenu clusterMenu = new JMenu("Clustering");
JMenuItem menuItemCPCLustering = new JMenuItem("Component Plane Clustering");
menuItemCPCLustering.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
ComponentPlaneClusteringFrame componentPlaneFrame = new ComponentPlaneClusteringFrame(
SOMViewer.this, getMap().getGsom(), state.inputDataObjects.getTemplateVector());
componentPlaneFrame.setLocation(state.controlElementsWidth, 0);
componentPlaneFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
componentPlaneFrame.pack();
componentPlaneFrame.setVisible(true);
} catch (SOMToolboxException ex) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(
"Error during Component Plane Clustering: " + ex.getMessage());
}
}
});
clusterMenu.add(menuItemCPCLustering);
JMenu menuMapClustering = new JMenu("Map Clustering");
clusterMenu.add(menuMapClustering);
clusterMethodGroup = new ButtonGroup();
JRadioButtonMenuItem menuItem = makeClusteringMenuItem("None", null, menuMapClustering);
clusterMethodGroup.add(menuItem);
menuItem.getModel().setSelected(true);
previousSelectedClusteringMethod = menuItem.getModel();
clusterMethodGroup.add(makeClusteringMenuItem("Single linkage", new SingleLinkageTreeBuilder(),
menuMapClustering));
clusterMethodGroup.add(makeClusteringMenuItem("Complete linkage", new CompleteLinkageTreeBuilder(),
menuMapClustering));
clusterMethodGroup.add(makeClusteringMenuItem("Ward's linkage (fast, inexact)", new WardsLinkageTreeBuilder(),
menuMapClustering));
clusterMethodGroup.add(makeClusteringMenuItem("Ward's linkage (exact)", new WardsLinkageTreeBuilderAll(),
menuMapClustering));
clusterMethodGroup.add(makeClusteringMenuItem("Ward's linkage (exact, experimental)",
new WardsLinkageTreeBuilderAll(true), menuMapClustering));
clusterMethodGroup.add(makeClusteringMenuItem("K-means", new KMeansTreeBuilder(), menuMapClustering));
menuBar.add(clusterMenu);
}
private JRadioButtonMenuItem makeClusteringMenuItem(String name, TreeBuilder builder, JMenu menuMapClustering) {
JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(name);
menuItem.addActionListener(new ClusteringMenuItemActionListener(builder));
menuMapClustering.add(menuItem);
return menuItem;
}
private AbstractButton makeToolbarButton(String imageName, String toolTipText, String altText) {
return UiUtils.setToolbarButtonDetails(new JButton(), this, imageName, toolTipText, altText, false);
}
private AbstractButton makeToolbarToggleButton(String imageName, String toolTipText, String altText,
boolean isSelected) {
return UiUtils.setToolbarButtonDetails(new JToggleButton(), this, imageName, toolTipText, altText, isSelected);
}
/**
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals(CENTER_AND_FIT_MAP)) {
mapPane.centerAndFitMapToScreen();
} else if (cmd.equals(RESET_DESKTOP_LAYOUT)) {
resetDesktopLayout();
} else if (cmd.equals(SELECT_LINE)) {
mapPane.setLine();
} else if (cmd.equals(SELECT_RECTANGLE)) {
mapPane.setRectangle();
} else if (cmd.equals(SELECT_CLUSTER)) {
mapPane.setCluster();
} else if (cmd.equals(MOVE_INPUT)) {
// rudi for moving inputs
mapPane.setInput();
} else if (cmd.equals(MOVE_LABEL)) {
// Angela
mapPane.setLabel();
} else if (cmd.equals(CREATE_LABEL)) {
// Angela
getMap().createLabel();
} else if (cmd.equals(TOGGLE_DATA)) {
state.dataVisibilityMode = ((AbstractButton) e.getSource()).isSelected();
getMap().reInitUnitDetails();
} else if (cmd.equals(TOGGLE_LABELS)) {
state.labelVisibilityMode = ((AbstractButton) e.getSource()).isSelected();
getMap().reInitUnitDetails();
} else if (cmd.equals(TOGGLE_HITS)) {
state.hitsVisibilityMode = ((AbstractButton) e.getSource()).isSelected();
getMap().reInitUnitDetails();
} else if (at.tuwien.ifs.somtoolbox.util.StringUtils.equalsAny(cmd, TOGGLE_PIE_CHARTS_MODES)) {
state.setClassPiechartMode(cmd);
classLegendPane.setEnabled(cmd != TOGGLE_PIE_CHARTS_NONE);
mapPane.updateClassSelection(null);
buttonPie.setIcon(TOGGLE_PIE_CHARTS_ICONS[ArrayUtils.indexOf(TOGGLE_PIE_CHARTS_MODES, cmd)]);
// buttonPie.setSelected(false);
} else if (cmd.equals(TOGGLE_EXACT_PLACEMENT)) {
state.exactUnitPlacement = ((AbstractButton) e.getSource()).isSelected();
getMap().reInitUnitDetails();
} else if (cmd.equals(TOGGLE_RELOCATE)) {
state.shiftOverlappingInputs = ((AbstractButton) e.getSource()).isSelected();
getMap().updatePointLocations();
} else if (cmd.equals(TOGGLE_LINKAGE)) {
state.displayInputLinkage = ((AbstractButton) e.getSource()).isSelected();
state.mapPNode.setLinkageVisibilityMode(state.displayInputLinkage);
} else if (cmd.equals(SOMVIEWER_3D)) {
Constructor<JInternalFrame> constr = null;
Object viewerState3D = null;
try {
// first do class-loading, to see if we have the optional components available
// load & instantiate state object of 3D
Class<?> classViewerState3D = Class.forName("at.tuwien.ifs.somtoolbox.apps.viewer3d.CommonSOMViewerStateData3D");
Constructor<?> constrViewerState3D = classViewerState3D.getConstructor(CommonSOMViewerStateData.class);
viewerState3D = constrViewerState3D.newInstance(state);
// load and instantiate 3D Viewer itself
@SuppressWarnings("unchecked")
Class<JInternalFrame> c = (Class<JInternalFrame>) Class.forName("at.tuwien.ifs.somtoolbox.apps.viewer3d.SOMViewer3D");
constr = c.getConstructor(classViewerState3D);
} catch (Exception e1) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").warning(
"SOMViever3D not available. To enable add the required classes to your classpath");
return;
}
try {
// now actually instantiate it
JInternalFrame somviewer3D = constr.newInstance(new Object[] { viewerState3D });
// desktop.add(somviewer3D);
somviewer3D.pack();
somviewer3D.setLocation(state.controlElementsWidth, 0);
somviewer3D.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
} catch (Exception e1) {
if (e1 instanceof SOMToolboxException) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(e1.getMessage());
} else {
if (e1 instanceof InvocationTargetException
&& ((InvocationTargetException) e1).getTargetException() instanceof SOMToolboxException) {
// happens when the SOMToolboxException is thrown in SOMViewer3D#init
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(
((InvocationTargetException) e1).getTargetException().getMessage());
} else {
e1.printStackTrace();
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(
"Error loading 3D Viewer: " + e1.getMessage());
}
}
}
}
}
public static void main(String[] args) {
// register and parse all options
JSAPResult config = AbstractOptionFactory.parseResults(args, OPTIONS);
new SOMViewer(config);
}
public void addVisualizationChangeListener(VisualizationChangeListener l) {
visChangeListeners.add(l);
}
public void removeVisualizationChangeListener(VisualizationChangeListener l) {
visChangeListeners.remove(l);
}
private void visualizationChangeFailure() {
visualizationMenuItemGroup.setSelected(oldSelectedVisualizationMenuItem, true);
}
private void visualizationChangeSuccess() {
oldSelectedVisualizationMenuItem = visualizationMenuItemGroup.getSelection();
for (VisualizationChangeListener listener : visChangeListeners) {
listener.visualisationChanged();
}
}
private class VisualizationActionListener implements ActionListener {
private int visualization;
private int variant;
public VisualizationActionListener(int vi, int va) {
super();
visualization = vi;
variant = va;
}
@Override
public void actionPerformed(ActionEvent e) {
final SwingWorker worker = new SwingWorker() {
@Override
public Object construct() {
try {
state.currentVariant = variant;
boolean success = mapPane.setVisualization(visualization, variant);
state.currentVariant = variant;
if (success) {
visControlPanel.updateVisualisationControl();
SOMViewer.this.visualizationChangeSuccess();
updatePalettePanel();
mapPane.repaint();
} else {
SOMViewer.this.visualizationChangeFailure();
}
} catch (SOMToolboxException e) {
JOptionPane.showMessageDialog(SOMViewer.this, e.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
return null;
}
};
worker.start(); // required for SwingWorker 3
}
}
@Override
@SuppressWarnings("deprecation")
public void update(Observable o, Object arg) {
menuPie.setEnabled(false);
if (arg instanceof SOMLibClassInformation && arg != null) { // we loaded a new class info
getMap().updateClassInfo((SOMLibClassInformation) arg);
classLegendPane.initClassTable();
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridwidth = GridBagConstraints.REMAINDER;
menuPie.setEnabled(true);
ThematicClassMapVisualizer tcmVis = getMap().getThematicClassMapVisualizer();
if (tcmVis != null) {
thematicClassRadioButton.setEnabled(true);
}
if (mapPane.getSecondMap() != null) {
mapPane.getSecondMap().updateClassInfo((SOMLibClassInformation) arg);
tcmVis = mapPane.getSecondMap().getThematicClassMapVisualizer();
if (tcmVis != null) {
thematicClassRadioButton.setEnabled(true);
}
}
} else {
state.setClassPiechartMode(TOGGLE_PIE_CHARTS_NONE);
getMap().updateClassInfo((SOMLibClassInformation) arg);
if (mapPane.getSecondMap() != null) {
mapPane.getSecondMap().updateClassInfo((SOMLibClassInformation) arg);
}
mapPane.updateClassSelection(null);
classLegendPane.initNoClassInfo();
thematicClassRadioButton.setEnabled(false);
}
}
public void updateSOMComparison(boolean haveData) {
boolean error = false;
try {
mapPane.updateSOMComparison();
} catch (SOMToolboxException e1) {
error = true;
}
if (haveData && !error) {
shiftsControlPanel.initGUIElements();
showShiftsMenuItem.setEnabled(true);
switchMapSubmenu.setEnabled(true);
} else {
shiftsControlPanel.initNoShiftsInfo();
showShiftsMenuItem.setEnabled(false);
switchMapSubmenu.setEnabled(false);
}
}
public void updatePaletteAfterEditing() {
try {
boolean success = getMap().reloadPaletteAfterEditing(getCurrentlySelectedPalette());
if (success) {
SOMViewer.this.visualizationChangeSuccess();
} else {
SOMViewer.this.visualizationChangeFailure();
}
showPalettePanel();
} catch (SOMToolboxException e) {
JOptionPane.showMessageDialog(SOMViewer.this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
public Palette getCurrentlySelectedPalette() {
return Palettes.getPaletteByName(paletteMenuItemGroup.getSelection().getActionCommand());
}
private class MyJCheckBoxMenuItem extends JCheckBoxMenuItem implements ActionListener {
private static final long serialVersionUID = 1L;
private Component component;
public MyJCheckBoxMenuItem(String name, Component component) {
super(name);
this.component = component;
setSelected(component.isVisible());
setMnemonic(name.charAt(0));
addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
component.setVisible(isSelected());
}
@Override
public Component getComponent() {
return component;
}
}
private class PaletteCheckboxMenuItemListener implements ActionListener {
private Palette palette;
public PaletteCheckboxMenuItemListener(Palette palette) {
this.palette = palette;
}
@Override
public void actionPerformed(ActionEvent e) {
try {
boolean success = getMap().changePalette(palette);
if (success) {
SOMViewer.this.visualizationChangeSuccess();
} else {
SOMViewer.this.visualizationChangeFailure();
}
// Angela: moved some code to showPalettePanel (clustering needs panel too)
showPalettePanel();
} catch (SOMToolboxException ex) {
JOptionPane.showMessageDialog(SOMViewer.this, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
}
private void initDocViewer(AbstractSelectionPanel sp) {
/** ** DocViewPanel *** */
DocViewPanel docviewer = new DocViewPanel();
docviewer.setDocumentPath(CommonSOMViewerStateData.fileNamePrefix);
docviewer.setDocumentSuffix(CommonSOMViewerStateData.fileNameSuffix);
sp.setItemListener(docviewer);
docViewerFrame = new JFrame("DocViewer") {
private static final long serialVersionUID = 1L;
@Override
public Dimension getPreferredSize() {
return new Dimension(450, 750);
}
};
// This does not work in Java 1.4
// FIXME: find another solution in 1.4
// docViewerFrame.setAlwaysOnTop(true);
docViewerFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
docViewerFrame.getContentPane().add(docviewer, BorderLayout.CENTER);
docViewerFrame.pack();
docViewerFrame.setVisible(true);
}
/**
* handles the window closing to dispose of a docviewer frame, if present, and not to do EXIT on close, but dispose.<br>
* If running standalone, the JVM will exit automatically after disposing the last frame, but if called from another
* application, this will only dispose this window, not exit the JVM.
*/
private void initWindowClosing() {
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // DISPOSE_ON_CLOSE); //EXIT_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
}
/**
* maybe there are some other windows we want to close too?
*/
@Override
public void windowClosing(WindowEvent e) {
if (!documentMode) {
System.exit(0);
}
System.out.println("closing");
if (docViewerFrame != null) {
docViewerFrame.setVisible(false);
docViewerFrame.dispose();
}
setVisible(false);
dispose();
}
});
}
public Color[] getClassLegendColors() {
return classLegendPane.getColors();
}
// Angela: shows or hides the palette panel
private void showPalettePanel() {
BackgroundImageVisualizer currentVisualization = mapPane.getCurrentVisualization();
if (currentVisualization != null || state.colorClusters) {
if (currentVisualization instanceof AbstractMatrixVisualizer) {
AbstractMatrixVisualizer vis = (AbstractMatrixVisualizer) currentVisualization;
palettePanel.setPalette(vis.getCurrentPalette().getColors(), vis.getMinimumMatrixValue(),
vis.getMaximumMatrixValue());
} else {
palettePanel.setPalette(getCurrentlySelectedPalette().getColors());
}
} else {
palettePanel.setPalette(null);
}
mapPane.repaint();
}
private void updatePalettePanel() {
BackgroundImageVisualizer curVis = mapPane.getCurrentVisualization();
if (curVis != null) {
if (curVis instanceof AbstractMatrixVisualizer) {
AbstractMatrixVisualizer matrixVis = (AbstractMatrixVisualizer) curVis;
if (matrixVis.getPalette() != null) {
reversePaletteMenuItem.setSelected(matrixVis.getCurrentPalette().isReversed());
palettePanel.setPalette(matrixVis.getPalette(), matrixVis.getMinimumMatrixValue(),
matrixVis.getMaximumMatrixValue());
}
}
} else {
palettePanel.setPalette(null);
}
}
public String getUnitDescriptionFileName() {
return unitDescriptionFileName;
}
public String getWeightVectorFileName() {
return weightVectorFileName;
}
public String getMapDescriptionFileName() {
return mapDescriptionFileName;
}
public CommonSOMViewerStateData getSOMViewerState() {
return state;
}
}