package org.chesmapper.view.gui; import java.awt.BorderLayout; import java.awt.Desktop; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import org.chesmapper.map.dataInterface.CompoundProperty; import org.chesmapper.map.dataInterface.NumericProperty; import org.chesmapper.map.dataInterface.CompoundPropertyUtil.NominalColoring; import org.chesmapper.map.main.Settings; import org.chesmapper.map.workflow.MappingWorkflow; import org.chesmapper.view.cluster.Cluster; import org.chesmapper.view.cluster.ClusterController; import org.chesmapper.view.cluster.Clustering; import org.chesmapper.view.cluster.Compound; import org.chesmapper.view.cluster.ExportData; import org.chesmapper.view.cluster.Clustering.SelectionListener; import org.chesmapper.view.gui.ViewControler.FeatureFilter; import org.chesmapper.view.gui.ViewControler.HighlightMode; import org.chesmapper.view.gui.table.CCDataTable; import org.chesmapper.view.gui.table.FeatureTable; import org.chesmapper.view.gui.table.TreeView; import org.chesmapper.view.gui.util.HideUnselectedDialog; import org.chesmapper.view.gui.util.SALIDialog; import org.mg.javalib.gui.TextPanel; import org.mg.javalib.gui.property.IntegerProperty; import org.mg.javalib.gui.property.Property; import org.mg.javalib.gui.property.PropertyPanel; import org.mg.javalib.util.ArrayUtil; import org.mg.javalib.util.CollectionUtil; import org.mg.javalib.util.SwingUtil; public class Actions { public static final String TOOLTIP = "tooltip"; private static Actions instance; public static Actions instance() { return instance; } public Actions(GUIControler guiControler, ViewControler viewControler, ClusterController clusterControler, Clustering clustering) { this.guiControler = guiControler; this.viewControler = viewControler; this.clustering = clustering; this.clusterControler = clusterControler; buildActions(); setAccelerators(); update(); installListeners(); instance = this; } private GUIControler guiControler; private ViewControler viewControler; private Clustering clustering; private ClusterController clusterControler; private final static String DATA_CLUSTER_TABLE = "file-cluster-table"; private final static String DATA_COMPOUND_TABLE = "file-compound-table"; private final static String DATA_FEATURE_TABLE = "file-feature-table"; private final static String[] DATA_ACTIONS = { DATA_CLUSTER_TABLE, DATA_COMPOUND_TABLE, DATA_FEATURE_TABLE }; private final static String FILE_NEW = "file-new"; private final static String FILE_EXIT = "file-exit"; private final static String[] FILE_ACTIONS = { FILE_NEW, FILE_EXIT }; private final static String FILTER_SELECTED = "filter-selected"; private final static String FILTER_UNSELECTED = "filter-unselected"; private final static String FILTER_CLUSTERS = "filter-clusters"; private final static String FILTER_COMPOUNDS = "filter-compounds"; private final static String[] FILTER_ACTIONS = { FILTER_SELECTED, FILTER_UNSELECTED, FILTER_CLUSTERS, FILTER_COMPOUNDS }; private final static String REMOVE_SELECTED = "remove-selected"; private final static String REMOVE_UNSELECTED = "remove-unselected"; private final static String REMOVE_CLUSTERS = "remove-clusters"; private final static String REMOVE_COMPOUNDS = "remove-compounds"; private final static String[] REMOVE_ACTIONS = { REMOVE_SELECTED, REMOVE_UNSELECTED, REMOVE_CLUSTERS, REMOVE_COMPOUNDS }; private final static String EDIT_SHOW_DISTANCE = "edit-show-distance"; private final static String EDIT_SHOW_SALI = "edit-show-sali"; private final static String EDIT_SUPERIMPOSE = "edit-superimpose"; private final static String EDIT_SELECT_LAST_FEATURE = "edit-select-last-feature"; private final static String EDIT_LOG_TRANSFORM = "edit-log-transform"; private final static String[] EDIT_ACTIONS = { EDIT_SUPERIMPOSE, EDIT_SHOW_DISTANCE, EDIT_SHOW_SALI, EDIT_SELECT_LAST_FEATURE, EDIT_LOG_TRANSFORM }; private final static String EXPORT_SELECTED = "export-selected"; private final static String EXPORT_UNSELECTED = "export-unselected"; private final static String EXPORT_CLUSTERS = "export-clusters"; private final static String EXPORT_COMPOUNDS = "export-compounds"; private final static String EXPORT_IMAGE = "export-image"; private final static String EXPORT_WORKFLOW = "export-workflow"; private final static String[] EXPORT_ACTIONS = { EXPORT_SELECTED, EXPORT_UNSELECTED, EXPORT_CLUSTERS, EXPORT_COMPOUNDS, EXPORT_IMAGE, EXPORT_WORKFLOW }; private final static String VIEW_HOME = "view-home"; private final static String VIEW_FULL_SCREEN = "view-full-screen"; private final static String VIEW_DRAW_HYDROGENS = "view-draw-hydrogens"; private final static String VIEW_SPIN = "view-spin"; private final static String VIEW_BLACK_WHITE = "view-black-white"; private final static String VIEW_ANTIALIAS = "view-antialias"; private final static String VIEW_COMPOUND_DESCRIPTOR = "view-compound-descriptor"; private final static String VIEW_HIDE_UNSELECTED_DIALOG = "view-hide-unselected"; private final static String VIEW_OPEN_SORT_FILTER_DIALOG = "view-open-sort-filter-dialog"; private final static String VIEW_SIZE_DIALOG = "view-size-dialog"; private final static String[] VIEW_ACTIONS = { VIEW_HOME, VIEW_FULL_SCREEN, VIEW_DRAW_HYDROGENS, VIEW_SPIN, VIEW_BLACK_WHITE, VIEW_ANTIALIAS, VIEW_COMPOUND_DESCRIPTOR, VIEW_OPEN_SORT_FILTER_DIALOG, VIEW_HIDE_UNSELECTED_DIALOG, VIEW_SIZE_DIALOG }; private final static String HIGHLIGHT_COLORS = "highlight-colors"; private final static String HIGHLIGHT_MODE = "highlight-mode"; private final static String HIGHLIGHT_LABELS = "highlight-labels"; private final static String HIGHLIGHT_LAST_FEATURE = "highlight-last-feature"; private final static String HIGHLIGHT_DECR_SPHERE_SIZE = "highlight-decr-sphere-size"; private final static String HIGHLIGHT_INCR_SPHERE_SIZE = "highlight-incr-sphere-size"; private final static String HIGHLIGHT_DECR_SPHERE_TRANSLUCENCY = "highlight-decr-sphere-translucency"; private final static String HIGHLIGHT_INCR_SPHERE_TRANSLUCENCY = "highlight-incr-sphere-translucency"; private final static String[] HIGHLIGHT_ACTIONS = { HIGHLIGHT_COLORS, HIGHLIGHT_LABELS, HIGHLIGHT_MODE, HIGHLIGHT_LAST_FEATURE }; private final static String[] HIGHLIGHT_SPHERE_ACTIONS = { HIGHLIGHT_DECR_SPHERE_SIZE, HIGHLIGHT_INCR_SPHERE_SIZE, HIGHLIGHT_DECR_SPHERE_TRANSLUCENCY, HIGHLIGHT_INCR_SPHERE_TRANSLUCENCY }; private final static String HELP_DOCU = "help-docu"; private final static String HELP_WARNINGS = "help-warnings"; private final static String HELP_ABOUT = "help-about"; private final static String[] HELP_ACTIONS = { HELP_DOCU, HELP_WARNINGS, HELP_ABOUT }; private final static String HIDDEN_UPDATE_MOUSE_SELECTION_PRESSED = "hidden-update-mouse-selection-pressed"; private final static String HIDDEN_UPDATE_MOUSE_SELECTION_RELEASED = "hidden-update-mouse-selection-released"; private final static String HIDDEN_DECR_COMPOUND_SIZE = "hidden-decr-compound-size"; private final static String HIDDEN_INCR_COMPOUND_SIZE = "hidden-incr-compound-size"; private final static String HIDDEN_ENABLE_JMOL_POPUP = "enable-jmol-popup"; private final static String HIDDEN_INCR_SPIN_SPEED = "incr-spin-speed"; private final static String HIDDEN_DECR_SPIN_SPEED = "decr-spin-speed"; private final static String HIDDEN_INCR_FONT_SIZE = "incr-font-size"; private final static String HIDDEN_DECR_FONT_SIZE = "decr-font-size"; private final static String HIDDEN_FILTER_FEATURES = "filter-features"; private final static String HIDDEN_TOGGLE_SORTING = "toggle-sorting"; private final static String HIDDEN_TREE = "tree"; private final static String HIDDEN_COPY = "copy"; private final static String HIDDEN_PREDICT = "predict"; private final static String HIDDEN_APP_DOMAIN = "app-domain"; private final static String HIDDEN_TOGGLE_NOM_HIGHLIGHT = "toggle-nom-highlight"; private final static String[] HIDDEN_ACTIONS = { HIDDEN_UPDATE_MOUSE_SELECTION_PRESSED, HIDDEN_UPDATE_MOUSE_SELECTION_RELEASED, HIDDEN_DECR_COMPOUND_SIZE, HIDDEN_INCR_COMPOUND_SIZE, HIDDEN_ENABLE_JMOL_POPUP, HIDDEN_INCR_SPIN_SPEED, HIDDEN_DECR_SPIN_SPEED, HIDDEN_INCR_FONT_SIZE, HIDDEN_DECR_FONT_SIZE, HIDDEN_FILTER_FEATURES, HIDDEN_TOGGLE_SORTING, HIDDEN_TREE, HIDDEN_COPY, HIDDEN_PREDICT, HIDDEN_APP_DOMAIN, HIDDEN_TOGGLE_NOM_HIGHLIGHT }; private HashMap<String, Action> actions = new LinkedHashMap<String, Action>(); private static HashMap<String, KeyStroke> keys = new HashMap<String, KeyStroke>(); static { keys.put(DATA_CLUSTER_TABLE, KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK)); keys.put(DATA_COMPOUND_TABLE, KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.ALT_MASK)); keys.put(DATA_FEATURE_TABLE, KeyStroke.getKeyStroke(KeyEvent.VK_3, ActionEvent.ALT_MASK)); keys.put(FILE_NEW, KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.ALT_MASK)); keys.put(FILE_EXIT, KeyStroke.getKeyStroke(KeyEvent.VK_F4, ActionEvent.ALT_MASK)); keys.put(EDIT_SHOW_DISTANCE, KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.ALT_MASK)); keys.put(EDIT_SUPERIMPOSE, KeyStroke.getKeyStroke(KeyEvent.VK_U, ActionEvent.ALT_MASK)); keys.put(EDIT_SELECT_LAST_FEATURE, KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.ALT_MASK)); keys.put(EDIT_LOG_TRANSFORM, KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.ALT_MASK)); keys.put(FILTER_SELECTED, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, ActionEvent.ALT_MASK)); keys.put(FILTER_UNSELECTED, KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, ActionEvent.ALT_MASK)); keys.put(EXPORT_IMAGE, KeyStroke.getKeyStroke(KeyEvent.VK_I, ActionEvent.ALT_MASK)); keys.put(EXPORT_WORKFLOW, KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.ALT_MASK)); keys.put(VIEW_HOME, KeyStroke.getKeyStroke("HOME")); keys.put(VIEW_DRAW_HYDROGENS, KeyStroke.getKeyStroke(KeyEvent.VK_H, ActionEvent.ALT_MASK)); // keys.put(VIEW_HIDE_UNSELECTED, KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.ALT_MASK)); keys.put(VIEW_SPIN, KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.ALT_MASK)); keys.put(VIEW_BLACK_WHITE, KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.ALT_MASK)); // keys.put(VIEW_COMPOUND_DESCRIPTOR, KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.ALT_MASK)); keys.put(HIDDEN_ENABLE_JMOL_POPUP, KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK)); keys.put(HIDDEN_UPDATE_MOUSE_SELECTION_PRESSED, KeyStroke.getKeyStroke(KeyEvent.VK_SHIFT, ActionEvent.SHIFT_MASK)); keys.put(HIDDEN_UPDATE_MOUSE_SELECTION_RELEASED, KeyStroke.getKeyStroke(KeyEvent.VK_SHIFT, 0, true)); keys.put(VIEW_ANTIALIAS, KeyStroke.getKeyStroke(KeyEvent.VK_G, ActionEvent.ALT_MASK)); keys.put(HIGHLIGHT_COLORS, KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.ALT_MASK)); keys.put(HIGHLIGHT_LAST_FEATURE, KeyStroke.getKeyStroke(KeyEvent.VK_F, ActionEvent.ALT_MASK)); keys.put(HIGHLIGHT_MODE, KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.ALT_MASK)); keys.put(HIDDEN_DECR_COMPOUND_SIZE, KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, ActionEvent.CTRL_MASK)); keys.put(HIDDEN_INCR_COMPOUND_SIZE, KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, ActionEvent.CTRL_MASK)); keys.put(HIGHLIGHT_DECR_SPHERE_SIZE, KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK)); keys.put(HIGHLIGHT_INCR_SPHERE_SIZE, KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK)); keys.put(HIGHLIGHT_INCR_SPHERE_TRANSLUCENCY, KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, ActionEvent.CTRL_MASK | ActionEvent.ALT_MASK)); keys.put(HIGHLIGHT_DECR_SPHERE_TRANSLUCENCY, KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, ActionEvent.CTRL_MASK | ActionEvent.ALT_MASK)); keys.put(HIDDEN_INCR_SPIN_SPEED, KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, ActionEvent.CTRL_MASK));// | ActionEvent.ALT_MASK)); keys.put(HIDDEN_DECR_SPIN_SPEED, KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, ActionEvent.CTRL_MASK));// | ActionEvent.ALT_MASK)); keys.put(HIDDEN_INCR_FONT_SIZE, KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, ActionEvent.ALT_MASK));// | ActionEvent.ALT_MASK)); keys.put(HIDDEN_DECR_FONT_SIZE, KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, ActionEvent.ALT_MASK));// | ActionEvent.ALT_MASK)); keys.put(HIDDEN_FILTER_FEATURES, KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK)); keys.put(HIDDEN_TOGGLE_SORTING, KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK)); keys.put(HIDDEN_TOGGLE_NOM_HIGHLIGHT, KeyStroke.getKeyStroke(KeyEvent.VK_E, ActionEvent.ALT_MASK)); keys.put(HIDDEN_TREE, KeyStroke.getKeyStroke(KeyEvent.VK_4, ActionEvent.ALT_MASK)); keys.put(HIDDEN_COPY, KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK)); keys.put(HIDDEN_PREDICT, KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK)); keys.put(HIDDEN_APP_DOMAIN, KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.ALT_MASK)); } private void updateFullScreenKey() { if (guiControler.isFullScreen()) keys.put(VIEW_FULL_SCREEN, KeyStroke.getKeyStroke("ESCAPE")); else keys.put(VIEW_FULL_SCREEN, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, ActionEvent.ALT_MASK)); } public static String keyStrokeToText(KeyStroke keystroke) { return KeyEvent.getKeyModifiersText(keystroke.getModifiers()) + " + " + new String(Character.toChars(keystroke.getKeyCode())); } public static String getIncrDecrFontSizeKeys() { if (keys.get(HIDDEN_INCR_FONT_SIZE).getKeyCode() == KeyEvent.VK_PLUS && keys.get(HIDDEN_DECR_FONT_SIZE).getKeyCode() == KeyEvent.VK_MINUS && keys.get(HIDDEN_INCR_FONT_SIZE).getModifiers() == keys.get(HIDDEN_DECR_FONT_SIZE).getModifiers()) { return KeyEvent.getKeyModifiersText(keys.get(HIDDEN_INCR_FONT_SIZE).getModifiers()) + " +/-"; } else throw new IllegalStateException(); } public static String getToggleSortingKey() { return keyStrokeToText(keys.get(HIDDEN_TOGGLE_SORTING)); } public static String getFilterFeaturesKey() { return keyStrokeToText(keys.get(HIDDEN_FILTER_FEATURES)); } private void installListeners() { clustering.addSelectionListener(new SelectionListener() { @Override public void compoundWatchedChanged(Compound[] c) { update(); } @Override public void compoundActiveChanged(Compound[] c) { update(); } @Override public void clusterWatchedChanged(Cluster c) { update(); } @Override public void clusterActiveChanged(Cluster c) { update(); } }); clustering.addListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { update(); } }); } private void update() { Compound selectedCompounds[] = new Compound[0]; Compound selectedCompound = null; if (clustering.isCompoundActive()) { selectedCompounds = clustering.getActiveCompounds(); selectedCompound = clustering.getActiveCompound(); } if (clustering.isCompoundWatched()) { selectedCompounds = ArrayUtil.removeDuplicates(Compound.class, ArrayUtil.concat(Compound.class, selectedCompounds, clustering.getWatchedCompounds())); selectedCompound = clustering.getWatchedCompound(); } Cluster selectedClusters[] = new Cluster[0]; if (clustering.numClusters() > 1 && clustering.isClusterWatched()) selectedClusters = new Cluster[] { clustering.getWatchedCluster() }; else if (clustering.numClusters() > 1 && clustering.isClusterActive()) selectedClusters = new Cluster[] { clustering.getActiveCluster() }; Cluster unselectedClusters[] = new Cluster[0]; if (selectedClusters.length > 0) { List<Cluster> unselectedClustersList = new ArrayList<Cluster>(clustering.getClusters()); for (Cluster cluster : selectedClusters) unselectedClustersList.remove(cluster); unselectedClusters = ArrayUtil.toArray(Cluster.class, unselectedClustersList); } Compound unselectedCompounds[] = new Compound[0]; if (selectedCompounds.length > 0) { List<Compound> unselectedCompoundsList = new ArrayList<Compound>(clustering.getCompounds(true)); for (Compound compound : selectedCompounds) unselectedCompoundsList.remove(compound); unselectedCompounds = ArrayUtil.toArray(Compound.class, unselectedCompoundsList); } String actionsX[] = new String[] { FILTER_SELECTED, FILTER_UNSELECTED, REMOVE_SELECTED, REMOVE_UNSELECTED, EXPORT_SELECTED, EXPORT_UNSELECTED }; String actionStrings[] = new String[] { "Hide", "Hide", "Remove", "Remove", "Export", "Export" }; boolean selectedX[] = new boolean[] { true, false, true, false, true, false }; for (int i = 0; i < selectedX.length; i++) { AbstractAction action = (AbstractAction) actions.get(actionsX[i]); boolean selected = selectedX[i]; String actionString = actionStrings[i] + " " + (selected ? "selected" : "unselected"); Cluster clusters[] = selected ? selectedClusters : unselectedClusters; Compound compounds[] = selected ? selectedCompounds : unselectedCompounds; action.putValue("Compound", new Compound[0]); action.putValue("Cluster", new Cluster[0]); if (compounds.length > 0) { action.putValue("Compound", compounds); if (compounds.length == 1) action.putValue(Action.NAME, actionString + " " + compounds[0]); else if (compounds.length > 1) action.putValue(Action.NAME, actionString + " " + compounds.length + " compounds"); action.setEnabled(true); } else if (clusters.length > 0) { action.putValue("Cluster", clusters); if (clusters.length == 1) action.putValue(Action.NAME, actionString + " " + clusters[0].getName()); else if (clusters.length > 1) action.putValue(Action.NAME, actionString + " " + clusters.length + " clusters"); action.setEnabled(true); } else { action.putValue(Action.NAME, actionString + " cluster/compound"); action.setEnabled(false); } } if (selectedCompounds.length > 0 && !clustering.isRandomEmbedding()) { actions.get(EDIT_SHOW_DISTANCE).setEnabled(true); String cName = selectedCompound.toString(); if (cName.length() > 22) cName = cName.substring(0, 20) + ".."; actions.get(EDIT_SHOW_DISTANCE).putValue(Action.NAME, "Distance to " + cName); } else { actions.get(EDIT_SHOW_DISTANCE).putValue(Action.NAME, "Distance to selected compound"); actions.get(EDIT_SHOW_DISTANCE).setEnabled(false); } actions.get(EDIT_SHOW_SALI).setEnabled(!clustering.isRandomEmbedding()); if (clustering.isClusterActive()) actions.get(EDIT_SUPERIMPOSE).setEnabled(viewControler.isSingleClusterSpreadable()); else actions.get(EDIT_SUPERIMPOSE).setEnabled(viewControler.isAllClustersSpreadable()); actions.get(HELP_WARNINGS).setEnabled(clustering.doCheSMappingWarningsExist()); } private void filter(AbstractAction action) { final Compound comps[] = (Compound[]) action.getValue("Compound"); final Cluster c[] = (Cluster[]) action.getValue("Cluster"); List<Compound> compounds = new ArrayList<Compound>(); if (comps.length > 0) compounds = ArrayUtil.toList(comps); else for (Cluster clust : c) for (Compound compound : clust.getCompounds()) compounds.add(compound); clusterControler.applyCompoundFilter(compounds, false); } private void remove(AbstractAction action) { final Compound comps[] = (Compound[]) action.getValue("Compound"); final Cluster c[] = (Cluster[]) action.getValue("Cluster"); Thread th = new Thread(new Runnable() { public void run() { if (comps.length > 0) clusterControler.removeCompounds(comps); else if (c.length > 0) clusterControler.removeCluster(c); } }); th.start(); } private void export(AbstractAction action) { final Compound comps[] = (Compound[]) action.getValue("Compound"); final Cluster c[] = (Cluster[]) action.getValue("Cluster"); if (comps.length > 0) { int[] compoundOrigIndices = new int[comps.length]; for (int i = 0; i < compoundOrigIndices.length; i++) compoundOrigIndices[i] = comps[i].getOrigIndex(); ExportData.exportCompoundsWithOrigIndices(clustering, compoundOrigIndices, viewControler.getCompoundDescriptor()); } else if (c.length > 0) { int[] clusterIndices = new int[c.length]; for (int i = 0; i < clusterIndices.length; i++) clusterIndices[i] = clustering.indexOf(c[i]); ExportData.exportClusters(clustering, clusterIndices, viewControler.getCompoundDescriptor()); } } private void setAccelerators() { updateFullScreenKey(); for (String action : actions.keySet()) { KeyStroke keyStroke = keys.get(action); if (keyStroke != null) ((AbstractAction) actions.get(action)).putValue(Action.ACCELERATOR_KEY, keyStroke); } } private abstract class ActionCreator { AbstractAction action; public ActionCreator(String s) { this(s, new String[0], new String[0]); } public ActionCreator(String s, String valueProperty) { this(s, valueProperty, null); } public ActionCreator(String s, String valueProperty, String enabledProperty) { this(s, valueProperty == null ? new String[0] : new String[] { valueProperty }, enabledProperty == null ? new String[0] : new String[] { enabledProperty }); } public ActionCreator(String s, final String valueProperty[], final String enabledProperty[]) { String name = null; String tooltip = null; if (ArrayUtil.indexOf(HIDDEN_ACTIONS, s) == -1) { name = Settings.text("action." + s); tooltip = "<html>" + Settings.text("action." + s + ".tooltip").replace("\n", "<br>") + "</html>"; } action = new AbstractAction(name) { @Override public void actionPerformed(ActionEvent e) { action(); } }; action.putValue(TOOLTIP, tooltip); action.putValue("is-radio-buttion", isRadio()); action.setEnabled(isEnabled()); if ((valueProperty != null && valueProperty.length > 0) || (enabledProperty != null && enabledProperty.length > 0)) { if (valueProperty != null && valueProperty.length > 0) action.putValue(Action.SELECTED_KEY, isSelected()); PropertyChangeListener l = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (ArrayUtil.indexOf(valueProperty, evt.getPropertyName()) != -1) action.putValue(Action.SELECTED_KEY, isSelected()); if (ArrayUtil.indexOf(enabledProperty, evt.getPropertyName()) != -1) action.setEnabled(isEnabled()); } }; guiControler.addPropertyChangeListener(l); viewControler.addViewListener(l); } actions.put(s, action); } public abstract void action(); protected boolean isRadio() { return false; } public boolean isEnabled() { return true; } public Boolean isSelected() { return null; } } // private abstract class RadioActionCreator extends ActionCreator // { // public RadioActionCreator(String s, String valueProperty) // { // super(s, valueProperty); // } // // public RadioActionCreator(String s, String valueProperty, String enabledProperty) // { // super(s, valueProperty, enabledProperty); // } // // protected boolean isRadio() // { // return true; // } // } private void buildActions() { new ActionCreator(FILE_NEW) { @Override public void action() { newClustering(); } }; new ActionCreator(DATA_CLUSTER_TABLE) { @Override public void action() { CCDataTable.show(viewControler, clusterControler, clustering, true); } }; new ActionCreator(DATA_COMPOUND_TABLE) { @Override public void action() { CCDataTable.show(viewControler, clusterControler, clustering, false); } }; new ActionCreator(DATA_FEATURE_TABLE) { @Override public void action() { new FeatureTable(viewControler, clusterControler, clustering); } }; new ActionCreator(FILE_EXIT) { @Override public void action() { JFrame f = null; if (viewControler instanceof JPanel) { java.awt.Container top = ((JPanel) viewControler).getTopLevelAncestor(); if (top instanceof JFrame) f = (JFrame) top; } LaunchCheSMapper.exit(f); } }; new ActionCreator(FILTER_SELECTED) { @Override public void action() { filter((AbstractAction) actions.get(FILTER_SELECTED)); } }; new ActionCreator(FILTER_UNSELECTED) { @Override public void action() { filter((AbstractAction) actions.get(FILTER_UNSELECTED)); } }; new ActionCreator(FILTER_CLUSTERS) { @Override public void action() { clusterControler.chooseClustersToFilter(); } }; new ActionCreator(FILTER_COMPOUNDS) { @Override public void action() { clusterControler.chooseCompoundsToFilter(); } }; new ActionCreator(REMOVE_SELECTED) { @Override public void action() { remove((AbstractAction) actions.get(REMOVE_SELECTED)); } }; new ActionCreator(REMOVE_UNSELECTED) { @Override public void action() { remove((AbstractAction) actions.get(REMOVE_UNSELECTED)); } }; new ActionCreator(REMOVE_CLUSTERS) { @Override public void action() { clusterControler.chooseClustersToRemove(); } }; new ActionCreator(REMOVE_COMPOUNDS) { @Override public void action() { clusterControler.chooseCompoundsToRemove(); } }; new ActionCreator(EXPORT_SELECTED) { @Override public void action() { export((AbstractAction) actions.get(EXPORT_SELECTED)); } }; new ActionCreator(EXPORT_UNSELECTED) { @Override public void action() { export((AbstractAction) actions.get(EXPORT_UNSELECTED)); } }; new ActionCreator(EXPORT_CLUSTERS) { @Override public void action() { clustering.chooseClustersToExport(viewControler.getCompoundDescriptor()); } }; new ActionCreator(EXPORT_COMPOUNDS) { @Override public void action() { clustering.chooseCompoundsToExport(viewControler.getCompoundDescriptor()); } }; new ActionCreator(EXPORT_IMAGE) { @Override public void action() { View.instance.exportImage(); } }; new ActionCreator(EXPORT_WORKFLOW) { @Override public void action() { MappingWorkflow.exportMappingWorkflowToFile(MappingWorkflow.exportSettingsToMappingWorkflow()); } }; new ActionCreator(VIEW_HOME) { @Override public void action() { viewControler.resetView(); } }; new ActionCreator(VIEW_FULL_SCREEN, GUIControler.PROPERTY_FULLSCREEN_CHANGED) { @Override public void action() { guiControler.setFullScreen(!guiControler.isFullScreen()); setAccelerators(); } @Override public Boolean isSelected() { return guiControler.isFullScreen(); } }; new ActionCreator(VIEW_DRAW_HYDROGENS, ViewControler.PROPERTY_SHOW_HYDROGENS) { @Override public void action() { viewControler.setHideHydrogens(!viewControler.isHideHydrogens()); } @Override public Boolean isSelected() { return !viewControler.isHideHydrogens(); } }; new ActionCreator(VIEW_HIDE_UNSELECTED_DIALOG) { @Override public void action() { HideUnselectedDialog.showDialog(viewControler, clustering); } }; new ActionCreator(VIEW_OPEN_SORT_FILTER_DIALOG) { @Override public void action() { viewControler.showSortFilterDialog(); } }; new ActionCreator(VIEW_SIZE_DIALOG) { IntegerProperty font; @Override public void action() { if (font == null) { font = new IntegerProperty("Font size (" + getIncrDecrFontSizeKeys() + ")", viewControler.getFontSize(), 6, 48); viewControler.addViewListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName().equals(ViewControler.PROPERTY_FONT_SIZE_CHANGED)) font.setValue(viewControler.getFontSize()); } }); font.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { viewControler.setFontSize(font.getValue()); } }); } guiControler.setAccentuateSizeComponents(true); JPanel p = new JPanel(new BorderLayout(10, 10)); p.add(new PropertyPanel(new Property[] { font }), BorderLayout.NORTH); JPanel pp = new JPanel(new BorderLayout(5, 5)); pp.add(new JLabel("Maximum width in percent:"), BorderLayout.NORTH); pp.add(new PropertyPanel(ComponentSize.MAX_WIDTH)); p.add(pp); SwingUtil.showInDialog(p, String.valueOf(action.getValue(Action.NAME)), null, null, Settings.TOP_LEVEL_FRAME); guiControler.setAccentuateSizeComponents(false); } }; new ActionCreator(VIEW_SPIN, ViewControler.PROPERTY_SPIN_CHANGED) { @Override public void action() { viewControler.setSpinEnabled(!viewControler.isSpinEnabled()); } @Override public Boolean isSelected() { return viewControler.isSpinEnabled(); } }; new ActionCreator(VIEW_BLACK_WHITE, ViewControler.PROPERTY_BACKGROUND_CHANGED) { @Override public void action() { viewControler.setBackgroundBlack(!viewControler.isBlackgroundBlack()); } @Override public Boolean isSelected() { return viewControler.isBlackgroundBlack(); } }; new ActionCreator(VIEW_ANTIALIAS, ViewControler.PROPERTY_ANTIALIAS_CHANGED) { @Override public void action() { viewControler.setAntialiasEnabled(!viewControler.isAntialiasEnabled()); } @Override public Boolean isSelected() { return viewControler.isAntialiasEnabled(); } }; new ActionCreator(VIEW_COMPOUND_DESCRIPTOR) { @Override public void action() { List<CompoundProperty> props = new ArrayList<CompoundProperty>(); props.add(ViewControler.COMPOUND_INDEX_PROPERTY); props.add(ViewControler.COMPOUND_SMILES_PROPERTY); for (CompoundProperty compoundProperty : clustering.getProperties()) props.add(compoundProperty); for (CompoundProperty compoundProperty : clustering.getFeatures()) if (!props.contains(compoundProperty)) props.add(compoundProperty); CompoundProperty selected = viewControler.getCompoundDescriptor(); CompoundProperty p = SwingUtil.selectFromListWithDialog(props, selected, "Set compound identifier", Settings.TOP_LEVEL_FRAME); if (p != null) viewControler.setCompoundDescriptor(p); } }; new ActionCreator(HELP_DOCU) { @Override public void action() { try { Desktop.getDesktop().browse(new URI(Settings.HOMEPAGE_DOCUMENTATION)); } catch (Exception ex) { Settings.LOGGER.error(ex); } } }; new ActionCreator(HELP_WARNINGS) { @Override public void action() { if (clustering.doCheSMappingWarningsExist()) clustering.showCheSMappingWarnings(); } }; new ActionCreator(HELP_ABOUT) { @Override public void action() { showAboutDialog(); } }; new ActionCreator(HIDDEN_ENABLE_JMOL_POPUP) { @Override public void action() { View.instance.scriptWait("set disablePopupMenu off"); } }; new ActionCreator(HIDDEN_UPDATE_MOUSE_SELECTION_PRESSED) { @Override public void action() { viewControler.updateMouseSelection(true); } }; new ActionCreator(HIDDEN_UPDATE_MOUSE_SELECTION_RELEASED) { @Override public void action() { viewControler.updateMouseSelection(false); } }; new ActionCreator(HIDDEN_DECR_COMPOUND_SIZE) { @Override public void action() { if (viewControler.canChangeCompoundSize(false)) viewControler.changeCompoundSize(false); } }; new ActionCreator(HIDDEN_INCR_COMPOUND_SIZE) { @Override public void action() { if (viewControler.canChangeCompoundSize(true)) viewControler.changeCompoundSize(true); } }; new ActionCreator(HIGHLIGHT_COLORS) { @Override public void action() { ColorEditor.start(viewControler, clustering); } }; new ActionCreator(HIGHLIGHT_LABELS, ViewControler.PROPERTY_HIGHLIGHT_CHANGED) { @Override public void action() { viewControler.setHighlighterLabelsVisible(!viewControler.isHighlighterLabelsVisible()); } @Override public Boolean isSelected() { return viewControler.isHighlighterLabelsVisible(); } }; new ActionCreator(HIGHLIGHT_LAST_FEATURE, ViewControler.PROPERTY_HIGHLIGHT_LAST_FEATURE, ViewControler.PROPERTY_HIGHLIGHT_MODE_CHANGED) { @Override public void action() { viewControler.setHighlightLastFeatureEnabled(!viewControler.isHighlightLastFeatureEnabled()); } @Override public Boolean isSelected() { return viewControler.isHighlightLastFeatureEnabled(); } @Override public boolean isEnabled() { return viewControler.getHighlightMode() == HighlightMode.Spheres; } }; new ActionCreator(EDIT_SUPERIMPOSE, ViewControler.PROPERTY_SUPERIMPOSE_CHANGED) { @Override public void action() { viewControler.setSuperimpose(!viewControler.isSuperimpose()); } @Override public Boolean isSelected() { return viewControler.isSuperimpose(); } }; new ActionCreator(EDIT_SELECT_LAST_FEATURE) { @Override public void action() { viewControler.setSelectLastSelectedHighlighter(); } }; new ActionCreator(HIGHLIGHT_MODE, ViewControler.PROPERTY_HIGHLIGHT_MODE_CHANGED, ViewControler.PROPERTY_STYLE_CHANGED) { @Override public void action() { viewControler .setHighlightMode((viewControler.getHighlightMode() != HighlightMode.Spheres) ? MainPanel.HighlightMode.Spheres : MainPanel.HighlightMode.ColorCompounds); } @Override public Boolean isSelected() { return viewControler.getHighlightMode() == MainPanel.HighlightMode.Spheres; } @Override public boolean isEnabled() { return viewControler.getStyle() != ViewControler.Style.dots; } }; new ActionCreator(HIGHLIGHT_DECR_SPHERE_SIZE, null, ViewControler.PROPERTY_HIGHLIGHT_MODE_CHANGED) { @Override public void action() { if (View.instance.sphereSize >= 0.1) viewControler.setSphereSize(View.instance.sphereSize - 0.1); else viewControler.setSphereSize(0); } @Override public boolean isEnabled() { return viewControler.getHighlightMode() == HighlightMode.Spheres; } }; new ActionCreator(HIGHLIGHT_INCR_SPHERE_SIZE, null, ViewControler.PROPERTY_HIGHLIGHT_MODE_CHANGED) { @Override public void action() { if (View.instance.sphereSize <= 0.9) viewControler.setSphereSize(View.instance.sphereSize + 0.1); else viewControler.setSphereSize(1); } @Override public boolean isEnabled() { return viewControler.getHighlightMode() == HighlightMode.Spheres; } }; new ActionCreator(HIGHLIGHT_DECR_SPHERE_TRANSLUCENCY, null, ViewControler.PROPERTY_HIGHLIGHT_MODE_CHANGED) { @Override public void action() { if (View.instance.sphereTranslucency >= 0.1) viewControler.setSphereTranslucency(View.instance.sphereTranslucency - 0.1); else viewControler.setSphereTranslucency(0); } @Override public boolean isEnabled() { return viewControler.getHighlightMode() == HighlightMode.Spheres; } }; new ActionCreator(HIGHLIGHT_INCR_SPHERE_TRANSLUCENCY, null, ViewControler.PROPERTY_HIGHLIGHT_MODE_CHANGED) { @Override public void action() { if (View.instance.sphereTranslucency <= 0.9) viewControler.setSphereTranslucency(View.instance.sphereTranslucency + 0.1); else viewControler.setSphereTranslucency(1); } @Override public boolean isEnabled() { return viewControler.getHighlightMode() == HighlightMode.Spheres; } }; new ActionCreator(HIDDEN_INCR_SPIN_SPEED) { @Override public void action() { viewControler.increaseSpinSpeed(true); } }; new ActionCreator(HIDDEN_DECR_SPIN_SPEED) { @Override public void action() { viewControler.increaseSpinSpeed(false); } }; new ActionCreator(HIDDEN_INCR_FONT_SIZE) { @Override public void action() { viewControler.increaseFontSize(true); } }; new ActionCreator(HIDDEN_DECR_FONT_SIZE) { @Override public void action() { viewControler.increaseFontSize(false); } }; new ActionCreator(HIDDEN_FILTER_FEATURES) { @Override public void action() { FeatureFilter filters[] = FeatureFilter.validValues(clustering); int idx = ArrayUtil.indexOf(filters, viewControler.getFeatureFilter()); if (idx < filters.length - 1) idx++; else idx = 0; viewControler.setFeatureFilter(filters[idx]); } }; new ActionCreator(HIDDEN_TOGGLE_SORTING) { @Override public void action() { viewControler.setFeatureSortingEnabled(!viewControler.isFeatureSortingEnabled()); } }; new ActionCreator(HIDDEN_TOGGLE_NOM_HIGHLIGHT) { @Override public void action() { int idx = ArrayUtil.indexOf(NominalColoring.values(), viewControler.getNominalColoring()); if (idx == NominalColoring.values().length - 1) idx = 0; else idx++; viewControler.setNominalColoring(NominalColoring.values()[idx]); } }; new ActionCreator(HIDDEN_TREE) { @Override public void action() { new TreeView(viewControler, clusterControler, clustering, guiControler); } }; new ActionCreator(HIDDEN_COPY) { @Override public void action() { if (guiControler.getSelectedString() != null && guiControler.getSelectedString().length() > 0) { StringSelection s = new StringSelection(guiControler.getSelectedString()); Clipboard system = Toolkit.getDefaultToolkit().getSystemClipboard(); system.setContents(s, s); String str = guiControler.getSelectedString(); guiControler.showMessage("Copy string to clipboard: '" + (str.length() > 50 ? str.substring(0, 48) + ".." : str) + "'"); } else guiControler.showMessage("Nothing selected for copying to clipboard"); } }; new ActionCreator(HIDDEN_PREDICT) { @Override public void action() { guiControler.block("predict"); try { clustering.predict(); } finally { guiControler.unblock("predict"); } } }; new ActionCreator(HIDDEN_APP_DOMAIN) { @Override public void action() { guiControler.block("app-domain"); try { clustering.computeAppDomain(); } finally { guiControler.unblock("app-domain"); } } }; new ActionCreator(EDIT_SHOW_DISTANCE) { @Override public void action() { guiControler.block("distance"); try { Compound c = null; if (clustering.isCompoundWatched()) c = clustering.getWatchedCompound(); else if (clustering.isCompoundActive()) c = clustering.getActiveCompound(); viewControler.setHighlighter(clustering.addDistanceToCompoundFeature(c)); } finally { guiControler.unblock("distance"); } } }; new ActionCreator(EDIT_SHOW_SALI) { @Override public void action() { SALIDialog.showDialog(viewControler, clustering, clusterControler); } }; new ActionCreator(EDIT_LOG_TRANSFORM, null, ViewControler.PROPERTY_HIGHLIGHT_CHANGED) { @Override public void action() { NumericProperty p = clustering.addLogFeature((NumericProperty) viewControler.getHighlightedProperty()); if (p != null) viewControler.setHighlighter(p); } @Override public boolean isEnabled() { return viewControler.getHighlightedProperty() instanceof NumericProperty; } }; } private void newClustering() { clusterControler.newClustering(); } public static void showAboutDialog() { TextPanel p = new TextPanel(); p.addHeading(Settings.TITLE); p.addTable(new String[][] { { "Version:", Settings.VERSION_STRING }, { "Homepage:", Settings.HOMEPAGE }, { "Contact:", Settings.CONTACT } }); p.setPreferredWith(600); JOptionPane.showMessageDialog(Settings.TOP_LEVEL_FRAME, p, "About " + Settings.TITLE, JOptionPane.INFORMATION_MESSAGE, Settings.CHES_MAPPER_IMAGE); } private Action[] getActions(String actionNames[]) { Action a[] = new Action[actionNames.length]; for (int i = 0; i < a.length; i++) a[i] = actions.get(actionNames[i]); return a; } public Action[] getFileActions() { return getActions(FILE_ACTIONS); } public Action[] getDataActions() { return getActions(DATA_ACTIONS); } public Action[] getEditActions() { return getActions(EDIT_ACTIONS); } public Action[] getExportActions() { return getActions(EXPORT_ACTIONS); } public Action[] getRemoveActions() { return getActions(REMOVE_ACTIONS); } public Action[] getFilterActions() { return getActions(FILTER_ACTIONS); } public Action[] getViewActions() { return getActions(VIEW_ACTIONS); } public Action[] getHighlightActions() { return getActions(HIGHLIGHT_ACTIONS); } public Action[] getHighlightSphereActions() { return getActions(HIGHLIGHT_SPHERE_ACTIONS); } public Action[] getHelpActions() { return getActions(HELP_ACTIONS); } public Action[] getHiddenActions() { return getActions(HIDDEN_ACTIONS); } public boolean performAction(final Object source, KeyStroke k, boolean onlyHidden) { for (final String a : (onlyHidden ? HIDDEN_ACTIONS : CollectionUtil.toArray(keys.keySet()))) { KeyStroke keyStroke = keys.get(a); if (keyStroke != null && keyStroke.equals(k) && actions.get(a).isEnabled()) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { actions.get(a).actionPerformed(new ActionEvent(source, -1, "")); } }); return true; } } return false; } public static void main(String args[]) { KeyStroke keystroke = KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.ALT_MASK); System.out.println(KeyEvent.getKeyModifiersText(keystroke.getModifiers())); System.out.println(Character.toChars(keystroke.getKeyCode())[0]); //showAboutDialog(); } }