/* * Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center * * 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.apache.org/licenses/LICENSE-2.0 * * 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 org.fhcrc.cpl.viewer.gui; import org.fhcrc.cpl.toolbox.datastructure.Pair; import org.fhcrc.cpl.viewer.feature.*; import org.fhcrc.cpl.viewer.feature.extraction.FeatureFinder; import org.fhcrc.cpl.viewer.util.SharedProperties; import org.fhcrc.cpl.toolbox.filehandler.TempFileManager; import org.fhcrc.cpl.toolbox.proteomics.MSRun; import org.fhcrc.cpl.viewer.gui.MSImageComponent; import org.fhcrc.cpl.viewer.CommandFileRunner; import org.fhcrc.cpl.viewer.Localizer; import org.fhcrc.cpl.viewer.Application; import org.fhcrc.cpl.toolbox.gui.HtmlViewerPanel; import org.fhcrc.cpl.toolbox.gui.ImagePanel; import org.fhcrc.cpl.toolbox.gui.widget.SplashFrame; import org.fhcrc.cpl.viewer.ViewerUserManualGenerator; import org.fhcrc.cpl.viewer.quant.gui.QuantitationReviewer; import org.fhcrc.cpl.toolbox.TextProvider; import org.fhcrc.cpl.toolbox.ApplicationContext; import org.fhcrc.cpl.toolbox.commandline.CommandLineModuleExecutionException; import org.fhcrc.cpl.toolbox.proteomics.feature.Spectrum; import org.fhcrc.cpl.toolbox.proteomics.feature.FeatureSet; import org.systemsbiology.jrap.stax.MZXMLFileInfo; import org.systemsbiology.jrap.stax.MSInstrumentInfo; import org.systemsbiology.jrap.stax.DataProcessingInfo; import org.systemsbiology.jrap.stax.SoftwareInfo; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import java.awt.*; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Clipboard; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.StringWriter; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Map; import java.util.TreeMap; import javax.imageio.ImageIO; /** * User: mbellew * Date: May 20, 2004 * Time: 3:01:47 PM */ public class WorkbenchFrame extends JFrame implements PropertyChangeListener { //hardcoded URLs for external support and help links public static final String SUPPORT_URL = "https://www.labkey.org/Project/msInspect/begin.view"; public static final String MSINSPECT_WEBSITE_URL = "https://proteomics.fhcrc.org/CPL/msinspect.html"; protected static String helpURL = MSINSPECT_WEBSITE_URL; private static String startup_appTitle = "msInspect"; private String appTitle = startup_appTitle; JMenuBar menuBar = null; JPanel panel2D = null; SpectrumComponent panelSpectrum = null; public JPanel contentPanel; public JLabel messageLabel; public JPanel statusPanel; public JScrollPane leftScrollPane; public JPanel bottomPane; public JSplitPane outerSplitPane; public JPanel rightPane; public GridBagConstraints rightPaneGBC; //Inner split pane, splits between properties pane and main image public JSplitPane topLeftSplitPane; //outer split pane, splits between topLeftSplitPane and detail pane public JSplitPane topRightSplitPane; public MSImageComponent imageComponent; public JPanel topPanel; public JTable propertiesTable; public JTree filesTree; protected DefaultMutableTreeNode filesRoot = new DefaultMutableTreeNode("NYI"); protected DefaultTreeModel filesModel = new DefaultTreeModel(filesRoot); public JTabbedPane infoTabbedPane; public JScrollPane propertiesScrollPane; protected PropertiesPane propertiesPane = new PropertiesPane(); // // Menu actions // // file public Action openFileAction = new OpenFileAction(null); public Action openFastaAction = new OpenFastaDialog.OpenFastaAction(null); public Action runInfoAction = new MSRunInfoAction("File Properties"); public Action saveImageAction = new MSImageComponent.SaveImageAction(); public Action exitAction = new ExitAction(); // tools public Action copyScanAction = new CopyScanAction(); public Action extractFeaturesAction = new ExtractFeatureRangesAction(); public FeatureSelectionFrame selectFeaturesAction = new FeatureSelectionFrame(); public Action displayHeatMapAction = new HeatMapAction(); public Action coverageCalculatorAction = new CoverageCalculatorAction(); public Action autoZoomAction = new AutoZoomAction(); public Action lockYAxisAction = new LockYAxisAction(); public Action singleScanExtractorAction = new ChooseFeatureExtractorAction("Single scan", FeatureStrategyWavelet.class); public Action centroidedScanExtractorAction = new ChooseFeatureExtractorAction("Centroided scan", FeatureStrategyCentroided.class) { { ApplicationContext.addPropertyChangeListener(SharedProperties.MS_RUN, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { MSRun run = (MSRun)evt.getNewValue(); boolean enabled = null == run || run.getHeaderInfo().getDataProcessing().getCentroided() != 1; setEnabled(enabled); } }); } }; public Action combinedExtractorAction = new ChooseFeatureExtractorAction("Combined", FeatureStrategyCombined.class); public Action grossFeaturesAction = new ChooseFeatureExtractorAction(" gross features (intermediate result)", FeatureStrategyGrossFeatures.class); public Action peakClustersExtractorAction = new ChooseFeatureExtractorAction("2D Peak Alignment", FeatureFinder.DEFAULT_FEATURE_FINDING_CLASS); public Action peaksExtractorAction = new ChooseFeatureExtractorAction(" peaks (intermediate result)", FeatureStrategyPeaks2.class); public Action detailOptionsDialogAction = new MSDetailPanel.ShowDialogAction(); public Action show3DWindowAction = new MSDetailPanel.Show3DAction(); public Action amtAction = new ProteinMatcherFrame.ProteinMatcherAction(); public Action runCommandFileAction = new CommandFileRunner.CommandFileRunnerAction(); public Action runCommandAction = new ChooseCommandDialog.RunCommandAction(); public Action showSelectedForCIDAction = new SelectedForCIDFinder.SelectedForCIDFinderAction(); public Action qurateAction = new QurateAction(); public Action featureViewerAction = new FeatureViewerAction(); // window public Action showPropertiesAction = new AbstractAction() { public void actionPerformed(ActionEvent e) { if (topLeftSplitPane.getDividerSize() > 0) hidePropertiesPane(); else showPropertiesPane(); } }; public Action showLayerTransparencyAction = new AbstractAction() { public void actionPerformed(ActionEvent e) { imageComponent.showLayerTransparencyDialog(); } }; // Languages public JMenu languageMenu; // Colors public JMenu colorMenu; // Fonts public JMenu fontMenu; // help public Action helpAction = new HelpAction(); public Action supportAction = new SupportAction(); public Action aboutAction = new AbstractAction("About") { public void actionPerformed(ActionEvent e) { WorkbenchFrame.ShowSplashScreen(); } }; public JMenuItem autoZoomMenuItem; public JMenuItem lockYAxisMenuItem; public JMenuItem defaultExtratorMenuItem; private static Image iconImage = null; public WorkbenchFrame() { super(startup_appTitle); try { Localizer.renderSwixml("org/fhcrc/cpl/viewer/gui/WorkbenchFrame.xml",this); assert null != contentPanel; } catch (Exception x) { ApplicationContext.errorMessage("error creating dialog", x); throw new RuntimeException(x); } String revision = (String) Application.getInstance().getProperty("REVISION"); if (null != revision) { if (revision.indexOf(' ') >= 0) revision = revision.substring(revision.indexOf(' ')).trim(); appTitle = appTitle + " (build " + revision + ")"; setTitle(appTitle); } setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); setContentPane(contentPanel); setSize(Localizer.adjustContainerDimension(new Dimension(800, 600))); //adjust the location of the divider between panes for the current locale topLeftSplitPane.setDividerLocation(Localizer.adjustContainerWidth(topLeftSplitPane.getDividerLocation())); try { iconImage = ImageIO.read(WorkbenchFrame.class.getResourceAsStream("icon.gif")); setIconImage(iconImage); } catch (Exception e) { } try { JMenuBar jmenu = (JMenuBar)Localizer.getSwingEngine(this).render("org/fhcrc/cpl/viewer/gui/WorkbenchFrameMenu.xml"); for (int i=0 ; i<jmenu.getMenuCount() ; i++) jmenu.getMenu(i).getPopupMenu().setLightWeightPopupEnabled(false); this.setJMenuBar(jmenu); autoZoomMenuItem.doClick(); defaultExtratorMenuItem.doClick(); } catch (Exception x) { ApplicationContext.errorMessage(TextProvider.getText("ERROR_LOADING_MENUS"), x); throw new RuntimeException(x); } //Localizer needs to populate all the language and font menu items Localizer.initializeLanguageMenu(languageMenu); Localizer.initializeFontMenu(fontMenu); //populate the available color schemes MSImageComponent.initializeColorMenu(colorMenu); imageComponent = new MSImageComponent(); ApplicationContext.setProperty("MSImageComponent", imageComponent); imageComponent.setScrollPane(leftScrollPane); MSDetailPanel detail = new MSDetailPanel(); // replace rightPane detail.setPreferredSize(rightPane.getPreferredSize()); detail.setMinimumSize(rightPane.getMinimumSize()); detail.setMaximumSize(rightPane.getMaximumSize()); topPanel.remove(rightPane); topPanel.add(detail, rightPaneGBC); //propertiesScrollPane.add(propertiesPane); infoTabbedPane.addTab(TextProvider.getText("PROPERTIES"), propertiesPane.getComponent()); panelSpectrum = new SpectrumComponent(); outerSplitPane.setBottomComponent(panelSpectrum.getComponent()); topRightSplitPane.setRightComponent(detail); topRightSplitPane.setLeftComponent(topLeftSplitPane); // UNDONE PLAF ?? messageLabel.setBackground(Color.WHITE); messageLabel.setFont(Font.decode("verdana plain 12")); messageLabel.setText(" "); ApplicationContext.addPropertyChangeListener(SharedProperties.MS_RUN, this); this.addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent event) { _resizeDivider(); } public void componentShown(ComponentEvent event) { super.componentShown(event); _resizeDivider(); } }); this.invalidate(); this.doLayout(); ApplicationContext.addPropertyChangeListener(SharedProperties.SELECTED, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { updateSelectedObject(evt.getNewValue()); } }); } public void hidePropertiesPane() { topLeftSplitPane.setDividerSize(0); topLeftSplitPane.setDividerLocation(0); topLeftSplitPane.setResizeWeight(0); infoTabbedPane.setVisible(false); } public void showPropertiesPane() { topLeftSplitPane.setDividerSize(5); int location = 200; if (topLeftSplitPane.getLastDividerLocation() > 20) location = topLeftSplitPane.getLastDividerLocation(); if (getWidth() > 200) location = Math.min(getWidth()-100, location); topLeftSplitPane.setDividerLocation(location); topLeftSplitPane.setResizeWeight(0.5); infoTabbedPane.setVisible(true); } protected void updateSelectedObject(Object o) { if (null == o) { } else if (o instanceof MSRun) { MSRun run = (MSRun)o; MZXMLFileInfo fileInfo = run.getHeaderInfo(); if (null == fileInfo) return; //HashMap m = new HashMap(30); ArrayList<Pair<String, String>> list = new ArrayList<Pair<String, String>>(); list.add(new Pair<String, String>(TextProvider.getText("FILE"), run.getFileName())); MSInstrumentInfo inst = fileInfo.getInstrumentInfo(); if (null != inst) { list.add(new Pair<String, String>("<html><b>" + TextProvider.getText("INSTRUMENT") + "<b></html>","")); list.add(new Pair<String, String>(TextProvider.getText("MANUFACTURER"), inst.getManufacturer())); list.add(new Pair<String, String>(TextProvider.getText("DETECTOR"), inst.getDetector())); list.add(new Pair<String, String>(TextProvider.getText("MASSANALYSER"), inst.getMassAnalyzer())); list.add(new Pair<String, String>(TextProvider.getText("MODEL"), inst.getModel())); list.add(new Pair<String, String>(TextProvider.getText("OPERATOR"), valueOf(inst.getOperator()))); if (inst.getSoftwareInfo() != null) { list.add(new Pair<String, String>(TextProvider.getText("SOFTWARE"), valueOf(inst.getSoftwareInfo().name))); } list.add(new Pair<String, String>(TextProvider.getText("IONIZATION"), inst.getIonization())); } DataProcessingInfo data = fileInfo.getDataProcessing(); if (null != data) // && (data.getCentroided() != -1 || data.getChargeDeconvoluted() != -1 || data.getDeisotoped() != -1)) { list.add(new Pair<String, String>("<html><b>" + TextProvider.getText("DATA_PROCESSING") + "<b></html>","")); list.add(new Pair<String, String>(TextProvider.getText("CENTROIDED"), String.valueOf(data.getCentroided()))); list.add(new Pair<String, String>(TextProvider.getText("CHARGE_DECONVOLUTED"), String.valueOf(data.getChargeDeconvoluted()))); list.add(new Pair<String, String>(TextProvider.getText("DEISOTOPED"), String.valueOf(data.getDeisotoped()))); list.add(new Pair<String, String>(TextProvider.getText("INTENSITY_CUTOFF"), String.valueOf(data.getIntensityCutoff()))); list.add(new Pair<String, String>(TextProvider.getText("SPOT_INTEGRATION"), String.valueOf(data.getSpotIntegration()))); java.util.List<SoftwareInfo> soft = data.getSoftwareUsed(); if (null != soft) { String key = TextProvider.getText("SOFTWARE"); for (int i=0 ; i<soft.size() ; i++) { list.add(new Pair<String, String>(key, valueOf(soft.get(i).name))); key = ""; } } } propertiesPane.setProperties(list); } else if (o instanceof FeatureSet) { FeatureSet fs = (FeatureSet)o; Map<Object,Object> tm = new TreeMap<Object,Object>(fs.getProperties()); java.util.List<Map.Entry<Object,Object>> list = new ArrayList<Map.Entry<Object,Object>>(); // add File to beginning of list if (fs.getSourceFile()!=null) list.add(new Pair<Object,Object>("File", fs.getSourceFile().getName())); list.addAll(tm.entrySet()); propertiesPane.setProperties(list); } else { propertiesPane.setProperties(o); } } static String valueOf(Object o) { return null == o ? "" : String.valueOf(o); } public static String getAppName() { return startup_appTitle; } private void _resizeDivider() { if (topLeftSplitPane.getDividerSize() == 0) // hidden topLeftSplitPane.setDividerLocation(0); /* int width = getContentPane().getWidth(); if (null != topLeftSplitPane) { int preferredWidth = 123; int dividerSize = topLeftSplitPane.getDividerSize(); int extra = 5;// = 10; int location = width-preferredWidth-dividerSize-extra; location = Math.max(100, location); topLeftSplitPane.setDividerLocation(location); } else { // rightPane.setSize(123, rightPane.getHeight()); } */ } /** * Handles all the Tools actions that select peptide finder types */ class ChooseFeatureExtractorAction extends AbstractAction { Class<?> _class; public ChooseFeatureExtractorAction(String text, Class<?> c) { super(null == text ? c.getName() : text); _class = c; } public void actionPerformed(ActionEvent event) { FeatureExtractor.setDefault(_class); Object source = event.getSource(); if (source instanceof JCheckBoxMenuItem) ((JCheckBoxMenuItem) source).setState(true); else if (source instanceof JRadioButtonMenuItem) ((JRadioButtonMenuItem) source).setSelected(true); } } /** * handles Tools->Copy Scan */ class CopyScanAction extends AbstractAction { public CopyScanAction() { super("Copy Scan"); } public void actionPerformed(ActionEvent event) { try { MSRun.MSScan scan = (MSRun.MSScan) ApplicationContext.getProperty(SharedProperties.MS_SCAN); if (null == scan) return; float[][] spectrum = scan.getSpectrum(); StringWriter sw = new StringWriter(); Spectrum.CopyToTSV(spectrum, sw, true); StringSelection sel = new StringSelection(sw.toString()); Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard(); clip.setContents(sel, sel); } catch (IOException x) { } } } /** * Handles the File->Exit action */ public class ExitAction extends AbstractAction { public ExitAction() { super("Exit"); } public void actionPerformed(ActionEvent event) { Application.quit(); } } public static class UrlAction extends AbstractAction { String url; UrlAction(String name, String url) { super(name); this.url = url; } public void actionPerformed(ActionEvent e) { try { HtmlViewerPanel.showURLInDialog(url, ""); return; } catch (IOException x) {; } JOptionPane.showConfirmDialog(null, url); } } /** * Handle selection of "Display Heat Map..." menu item */ public class HeatMapAction extends AbstractAction implements PropertyChangeListener { public HeatMapAction() { super("Display Heat Map..."); ApplicationContext.addPropertyChangeListener(SharedProperties.FEATURE_RANGES, this); setEnabled(null != HeatMapFrame.getDisplayedFeatureSet()); } public void actionPerformed(ActionEvent evt) { if (null == HeatMapFrame.getDisplayedFeatureSet()) { ApplicationContext.errorMessage("No feature set currently displayed.", null); return; } HeatMapFrame.getInstance().display(); return; } public void propertyChange(PropertyChangeEvent event) { setEnabled(null != HeatMapFrame.getDisplayedFeatureSet()); } } /** * Handles the Auto Zoom checkbox */ public class AutoZoomAction extends AbstractAction { public AutoZoomAction() { super("Auto zoom"); } public void actionPerformed(ActionEvent event) { Boolean zoomProperty = (Boolean) ApplicationContext.getProperty(SharedProperties.AUTO_ZOOM); boolean zoom = null != zoomProperty ? !zoomProperty.booleanValue() : true; Object source = event.getSource(); if (source instanceof JCheckBoxMenuItem) { JCheckBoxMenuItem menu = (JCheckBoxMenuItem) event.getSource(); menu.setState(zoom); } ApplicationContext.setProperty(SharedProperties.AUTO_ZOOM, new Boolean(zoom)); } } /** * Handles the "Lock Y Scale" checkbox */ public class LockYAxisAction extends AbstractAction { public LockYAxisAction() { super("Lock Y Axis"); } public void actionPerformed(ActionEvent event) { Boolean lockProperty = (Boolean) ApplicationContext.getProperty(SharedProperties.LOCK_Y_AXIS); boolean lock = null != lockProperty ? !lockProperty.booleanValue() : true; Object source = event.getSource(); if (source instanceof JCheckBoxMenuItem) { JCheckBoxMenuItem menu = (JCheckBoxMenuItem) event.getSource(); menu.setState(lock); } ApplicationContext.setProperty(SharedProperties.LOCK_Y_AXIS, new Boolean(lock)); } } public static class HelpAction extends UrlAction { public HelpAction() { super("Help Topics", helpURL); } public void actionPerformed(ActionEvent e) { File helpFile = TempFileManager.createTempFile("help.html", this); if (!helpFile.exists()) { try { PrintWriter helpPW = new PrintWriter(helpFile); new ViewerUserManualGenerator().generateFullManual(helpPW); helpURL = "file://" + helpFile.getAbsolutePath(); this.url = helpURL; } catch (Exception ex) { ApplicationContext.setMessage("Failed to generate user manual, defaulting to msInspect website"); } } super.actionPerformed(e); } } public static class SupportAction extends UrlAction { public SupportAction() { super("Support Forum", SUPPORT_URL); } } public void setMessage(String message) { if (EventQueue.isDispatchThread()) { if (null == message || 0 == message.length()) message = " "; messageLabel.setText(message); } else { final String msg = message; EventQueue.invokeLater(new Runnable() { public void run() { setMessage(msg); } }); } } public void disposeNoExit() { super.dispose(); } public void dispose() { System.exit(0); } public void propertyChange(PropertyChangeEvent event) { if (SharedProperties.MS_RUN.equals(event.getPropertyName())) { MSRun run = (MSRun)event.getNewValue(); if (null == run) setTitle(appTitle); else { String name = run.getFileName(); setTitle(appTitle + " -- " + name); } } } public static JFrame ShowSplashScreen() { SplashFrame splashFrame = new SplashFrame(WorkbenchFrame.class.getResource("splash.gif")); splashFrame.setVisible(true); return splashFrame; } public static class QurateAction extends AbstractAction { public void actionPerformed(ActionEvent event) { QuantitationReviewer quantReviewer = new QuantitationReviewer(); quantReviewer.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); quantReviewer.setVisible(true); } } }