io.github.mzmine.modules.plots.msspectrum.MsSpectrumPlotWindowController.java Source code

Java tutorial

Introduction

Here is the source code for io.github.mzmine.modules.plots.msspectrum.MsSpectrumPlotWindowController.java

Source

/*
 * Copyright 2006-2015 The MZmine 3 Development Team
 * 
 * This file is part of MZmine 3.
 * 
 * MZmine 3 is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License as published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 * 
 * MZmine 3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with MZmine 3; if not,
 * write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 * USA
 */

package io.github.mzmine.modules.plots.msspectrum;

import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Stroke;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javax.annotation.Nonnull;

import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.labels.XYItemLabelGenerator;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.AbstractXYItemRenderer;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.RangeType;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;

import com.google.common.base.Preconditions;
import com.google.common.collect.Range;

import io.github.msdk.datamodel.datastore.DataPointStore;
import io.github.msdk.datamodel.datastore.DataPointStoreFactory;
import io.github.msdk.datamodel.files.FileType;
import io.github.msdk.datamodel.msspectra.MsSpectrum;
import io.github.msdk.datamodel.msspectra.MsSpectrumType;
import io.github.msdk.datamodel.rawdata.IsolationInfo;
import io.github.msdk.datamodel.rawdata.MsFunction;
import io.github.msdk.datamodel.rawdata.MsScan;
import io.github.msdk.datamodel.rawdata.RawDataFile;
import io.github.msdk.io.mgf.MgfFileExportMethod;
import io.github.msdk.io.msp.MspExportAlgorithm;
import io.github.msdk.io.mzml.MzMLFileExportMethod;
import io.github.msdk.io.txt.TxtExportAlgorithm;
import io.github.msdk.io.txt.TxtImportAlgorithm;
import io.github.msdk.spectra.isotopepattern.IsotopePatternGeneratorAlgorithm;
import io.github.msdk.spectra.splash.SplashCalculationAlgorithm;
import io.github.msdk.util.MsScanUtil;
import io.github.mzmine.datamodel.MSDKObjectBuilder;
import io.github.mzmine.gui.MZmineGUI;
import io.github.mzmine.main.MZmineCore;
import io.github.mzmine.modules.plots.chromatogram.ChromatogramPlotModule;
import io.github.mzmine.modules.plots.chromatogram.ChromatogramPlotParameters;
import io.github.mzmine.modules.plots.isotopepattern.IsotopePatternPlotModule;
import io.github.mzmine.modules.plots.isotopepattern.IsotopePatternPlotParameters;
import io.github.mzmine.modules.plots.msspectrum.datasets.MsSpectrumDataSet;
import io.github.mzmine.modules.plots.spectrumparser.SpectrumParserPlotModule;
import io.github.mzmine.modules.plots.spectrumparser.SpectrumParserPlotParameters;
import io.github.mzmine.parameters.ParameterSet;
import io.github.mzmine.parameters.parametertypes.selectors.RawDataFilesSelection;
import io.github.mzmine.parameters.parametertypes.selectors.ScanSelection;
import io.github.mzmine.project.MZmineProject;
import io.github.mzmine.util.JavaFXUtil;
import io.github.mzmine.util.MsScanUtils;
import io.github.mzmine.util.jfreechart.ChartNodeJFreeChart;
import io.github.mzmine.util.jfreechart.IntelligentItemLabelGenerator;
import io.github.mzmine.util.jfreechart.JFreeChartUtils;
import io.github.mzmine.util.jfreechart.JFreeChartUtils.ImgFileType;
import io.github.mzmine.util.jfreechart.ManualZoomDialog;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Cursor;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextInputDialog;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;

/**
 * MS spectrum plot window
 */
public class MsSpectrumPlotWindowController {

    // Colors
    private static final Color gridColor = Color.rgb(220, 220, 220, 0.5);
    private static final Color labelsColor = Color.BLACK;
    private static final Color backgroundColor = Color.WHITE;
    private static final Color[] plotColors = { Color.rgb(0, 0, 192), // blue
            Color.rgb(192, 0, 0), // red
            Color.rgb(0, 192, 0), // green
            Color.MAGENTA, Color.CYAN, Color.ORANGE };

    private static final Font titleFont = new Font("SansSerif", Font.BOLD, 12);

    private static final String LAYERS_DIALOG_FXML = "MsSpectrumLayersDialog.fxml";

    private final ObservableList<MsSpectrumDataSet> datasets = FXCollections.observableArrayList();
    private int numberOfDataSets = 0;

    private final DoubleProperty mzShift = new SimpleDoubleProperty(this, "mzShift", 0.0);
    private final BooleanProperty itemLabelsVisible = new SimpleBooleanProperty(this, "itemLabelsVisible", true);
    private final BooleanProperty legendVisible = new SimpleBooleanProperty(this, "legendVisible", true);

    private File lastSaveDirectory;

    private TextTitle chartTitle, chartSubTitle;

    @FXML
    private BorderPane chartPane;

    @FXML
    private ChartNodeJFreeChart chartNode;

    @FXML
    private MenuItem setToMenuItem, showXICMenuItem;

    @FXML
    private Menu findMSMSMenu, removeDatasetMenu;

    public void initialize() {

        final JFreeChart chart = chartNode.getChart();
        final XYPlot plot = chart.getXYPlot();

        // Do not set colors and strokes dynamically. They are instead provided
        // by the dataset and configured in configureRenderer()
        plot.setDrawingSupplier(null);
        plot.setDomainGridlinePaint(JavaFXUtil.convertColorToAWT(gridColor));
        plot.setRangeGridlinePaint(JavaFXUtil.convertColorToAWT(gridColor));
        plot.setBackgroundPaint(JavaFXUtil.convertColorToAWT(backgroundColor));
        plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
        plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
        plot.setDomainCrosshairVisible(false);
        plot.setRangeCrosshairVisible(false);

        // chart properties
        chart.setBackgroundPaint(JavaFXUtil.convertColorToAWT(backgroundColor));

        // legend properties
        LegendTitle legend = chart.getLegend();
        // legend.setItemFont(legendFont);
        legend.setFrame(BlockBorder.NONE);

        // set the X axis (m/z) properties
        NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
        xAxis.setLabel("m/z");
        xAxis.setUpperMargin(0.03);
        xAxis.setLowerMargin(0.03);
        xAxis.setRangeType(RangeType.POSITIVE);
        xAxis.setTickLabelInsets(new RectangleInsets(0, 0, 20, 20));

        // set the Y axis (intensity) properties
        NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
        yAxis.setLabel("Intensity");
        yAxis.setRangeType(RangeType.POSITIVE);
        yAxis.setAutoRangeIncludesZero(true);

        // set the fixed number formats, because otherwise JFreeChart sometimes
        // shows exponent, sometimes it doesn't
        DecimalFormat mzFormat = MZmineCore.getConfiguration().getMZFormat();
        xAxis.setNumberFormatOverride(mzFormat);
        DecimalFormat intensityFormat = MZmineCore.getConfiguration().getIntensityFormat();
        yAxis.setNumberFormatOverride(intensityFormat);

        chartTitle = chartNode.getChart().getTitle();
        chartTitle.setMargin(5, 0, 0, 0);
        chartTitle.setFont(titleFont);

        chartNode.setCursor(Cursor.CROSSHAIR);

        // Remove the dataset if it is removed from the list
        datasets.addListener((Change<? extends MsSpectrumDataSet> c) -> {
            while (c.next()) {
                if (c.wasRemoved()) {
                    for (MsSpectrumDataSet ds : c.getRemoved()) {
                        int index = plot.indexOf(ds);
                        plot.setDataset(index, null);
                    }
                }
            }
        });

        itemLabelsVisible.addListener((prop, oldVal, newVal) -> {
            for (MsSpectrumDataSet dataset : datasets) {
                int datasetIndex = plot.indexOf(dataset);
                XYItemRenderer renderer = plot.getRenderer(datasetIndex);
                renderer.setBaseItemLabelsVisible(newVal);
            }
        });

        legendVisible.addListener((prop, oldVal, newVal) -> {
            legend.setVisible(newVal);
        });

    }

    /**
     * Add a new spectrum to the plot.
     * 
     * @param spectrum
     */
    public void addSpectrum(@Nonnull MsSpectrum spectrum, @Nonnull String name) {

        Preconditions.checkNotNull(spectrum);

        if (!Platform.isFxApplicationThread()) {
            throw new IllegalStateException(
                    "Not on FX application thread; currentThread = " + Thread.currentThread().getName());
        }

        MsSpectrumDataSet newDataSet = new MsSpectrumDataSet(spectrum, name);
        newDataSet.mzShiftProperty().bind(mzShift);
        datasets.add(newDataSet);

        final int datasetIndex = numberOfDataSets;
        numberOfDataSets++;

        final XYPlot plot = chartNode.getChart().getXYPlot();

        final Color newColor = plotColors[datasetIndex % plotColors.length];
        newDataSet.setColor(newColor);

        configureRenderer(newDataSet, datasetIndex);

        newDataSet.renderingTypeProperty().addListener(e -> {
            Platform.runLater(() -> configureRenderer(newDataSet, datasetIndex));
        });
        newDataSet.colorProperty().addListener(e -> {
            Platform.runLater(() -> configureRenderer(newDataSet, datasetIndex));
        });
        newDataSet.lineThicknessProperty().addListener(e -> {
            Platform.runLater(() -> configureRenderer(newDataSet, datasetIndex));
        });
        newDataSet.showDataPointsProperty().addListener(e -> {
            Platform.runLater(() -> configureRenderer(newDataSet, datasetIndex));
        });

        // Once everything is configured, add the dataset to the plot
        plot.setDataset(datasetIndex, newDataSet);

    }

    private void configureRenderer(MsSpectrumDataSet dataset, int datasetIndex) {

        final MsSpectrumType renderingType = dataset.getRenderingType();
        final XYPlot plot = chartNode.getChart().getXYPlot();

        // Set renderer
        AbstractXYItemRenderer newRenderer;
        switch (renderingType) {
        case PROFILE:
        case THRESHOLDED:
            XYLineAndShapeRenderer newLineRenderer = new XYLineAndShapeRenderer();
            final int lineThickness = dataset.getLineThickness();
            newLineRenderer.setBaseShape(new Ellipse2D.Double(-2 * lineThickness, -2 * lineThickness,
                    4 * lineThickness + 1, 4 * lineThickness + 1));
            newLineRenderer.setBaseShapesFilled(true);
            newLineRenderer.setBaseShapesVisible(dataset.getShowDataPoints());
            newLineRenderer.setDrawOutlines(false);

            Stroke baseStroke = new BasicStroke(lineThickness);
            newLineRenderer.setBaseStroke(baseStroke);
            newRenderer = newLineRenderer;
            break;
        case CENTROIDED:
        default:
            XYBarRenderer newBarRenderer = new XYBarRenderer();
            // Avoid gradients
            newBarRenderer.setBarPainter(new StandardXYBarPainter());
            newBarRenderer.setShadowVisible(false);
            newRenderer = newBarRenderer;
            break;
        }

        // Set tooltips for legend
        newRenderer.setLegendItemToolTipGenerator((ds, series) -> {
            if (ds instanceof MsSpectrumDataSet) {
                return ((MsSpectrumDataSet) ds).getDescription();
            } else
                return null;
        });

        // Set color
        Color baseColor = dataset.getColor();
        newRenderer.setBasePaint(JavaFXUtil.convertColorToAWT(baseColor));

        // Set label generator
        XYItemLabelGenerator intelligentLabelGenerator = new IntelligentItemLabelGenerator(chartNode, 100, dataset);
        newRenderer.setBaseItemLabelGenerator(intelligentLabelGenerator);
        newRenderer.setBaseItemLabelPaint(JavaFXUtil.convertColorToAWT(labelsColor));
        newRenderer.setBaseItemLabelsVisible(itemLabelsVisible.get());

        // Set tooltip generator
        newRenderer.setBaseToolTipGenerator(dataset);

        plot.setRenderer(datasetIndex, newRenderer);

    }

    public void handleAddScan(Event e) {
        ParameterSet parameters = MZmineCore.getConfiguration().getModuleParameters(MsSpectrumPlotModule.class);
        ButtonType exitCode = parameters.showSetupDialog("Add scan");
        if (exitCode != ButtonType.OK)
            return;

        final RawDataFilesSelection fileSelection = parameters.getParameter(MsSpectrumPlotParameters.inputFiles)
                .getValue();
        final Integer scanNumber = parameters.getParameter(MsSpectrumPlotParameters.scanNumber).getValue();
        final ScanSelection scanSelection = new ScanSelection(Range.singleton(scanNumber), null, null, null, null,
                null);
        final List<RawDataFile> dataFiles = fileSelection.getMatchingRawDataFiles();
        boolean spectrumAdded = false;
        for (RawDataFile dataFile : dataFiles) {
            for (MsScan scan : scanSelection.getMatchingScans(dataFile)) {
                String title = MsScanUtils.createSingleLineMsScanDescription(scan);
                addSpectrum(scan, title);
                spectrumAdded = true;
            }
        }
        if (!spectrumAdded) {
            MZmineGUI.displayMessage("Scan not found");
        }
    }

    public void handleAddSpectrumFromText(Event e) {
        ParameterSet parameters = MZmineCore.getConfiguration().getModuleParameters(SpectrumParserPlotModule.class);
        ButtonType exitCode = parameters.showSetupDialog("Parse spectrum");
        if (exitCode != ButtonType.OK)
            return;

        final String spectrumText = parameters.getParameter(SpectrumParserPlotParameters.spectrumText).getValue();
        final MsSpectrumType spectrumType = parameters.getParameter(SpectrumParserPlotParameters.spectrumType)
                .getValue();

        Preconditions.checkNotNull(spectrumText);
        Preconditions.checkNotNull(spectrumType);

        final MsSpectrum spectrum = TxtImportAlgorithm.parseMsSpectrum(spectrumText);
        spectrum.setSpectrumType(spectrumType);

        String spectrumName = "Manual spectrum";

        addSpectrum(spectrum, spectrumName);
    }

    public void handleAddIsotopePattern(Event e) {
        ParameterSet parameters = MZmineCore.getConfiguration().getModuleParameters(IsotopePatternPlotModule.class);
        ButtonType exitCode = parameters.showSetupDialog("Add isotope pattern");
        if (exitCode != ButtonType.OK)
            return;
        final String formula = parameters.getParameter(IsotopePatternPlotParameters.formula).getValue();
        final Double mzTolerance = parameters.getParameter(IsotopePatternPlotParameters.mzTolerance).getValue();
        final Double minAbundance = parameters.getParameter(IsotopePatternPlotParameters.minAbundance).getValue();
        final Double normalizedIntensity = parameters.getParameter(IsotopePatternPlotParameters.normalizedIntensity)
                .getValue();
        final MsSpectrum pattern = IsotopePatternGeneratorAlgorithm.generateIsotopes(formula, minAbundance,
                normalizedIntensity.floatValue(), mzTolerance);
        addSpectrum(pattern, formula);
    }

    public void handlePreviousScan(Event e) {
        for (MsSpectrumDataSet dataset : datasets) {
            MsSpectrum spectrum = dataset.getSpectrum();
            if (!(spectrum instanceof MsScan))
                continue;
            MsScan scan = (MsScan) spectrum;
            RawDataFile rawFile = scan.getRawDataFile();
            if (rawFile == null)
                return;
            int scanIndex = rawFile.getScans().indexOf(scan);
            if (scanIndex <= 0)
                return;
            MsScan prevScan = rawFile.getScans().get(scanIndex - 1);
            String title = MsScanUtils.createSingleLineMsScanDescription(prevScan);
            dataset.setSpectrum(prevScan, title);
        }
    }

    public void handleNextScan(Event e) {
        for (MsSpectrumDataSet dataset : datasets) {
            MsSpectrum spectrum = dataset.getSpectrum();
            if (!(spectrum instanceof MsScan))
                continue;
            MsScan scan = (MsScan) spectrum;
            RawDataFile rawFile = scan.getRawDataFile();
            if (rawFile == null)
                return;
            int scanIndex = rawFile.getScans().indexOf(scan);
            if (scanIndex == rawFile.getScans().size() - 1)
                return;
            MsScan nextScan = rawFile.getScans().get(scanIndex + 1);
            String title = MsScanUtils.createSingleLineMsScanDescription(nextScan);
            dataset.setSpectrum(nextScan, title);
        }
    }

    public void handleChartKeyPressed(KeyEvent e) {
        final KeyCode key = e.getCode();
        switch (key) {
        case RIGHT:
            handleNextScan(e);
            e.consume();
            break;
        case LEFT:
            handlePreviousScan(e);
            e.consume();
            break;
        case F:
            handleZoomOut(e);
            e.consume();
            break;
        case M:
            handleManualZoom(e);
            e.consume();
            break;
        case S:
            handleSetupLayers(e);
            e.consume();
            break;
        default:
        }

    }

    public void handleChartMousePressed(Event e) {
        chartNode.requestFocus();
    }

    public void handleSetupLayers(Event event) {
        try {
            URL layersDialogFXML = getClass().getResource(LAYERS_DIALOG_FXML);
            FXMLLoader loader = new FXMLLoader(layersDialogFXML);
            Stage layersDialog = loader.load();
            MsSpectrumLayersDialogController controller = loader.getController();
            controller.configure(datasets, this);
            layersDialog.initModality(Modality.APPLICATION_MODAL);
            layersDialog.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void handleToggleLabels(Event event) {
        itemLabelsVisible.set(!itemLabelsVisible.get());
    }

    public void handleToggleLegend(Event event) {
        legendVisible.set(!legendVisible.get());
    }

    public void handleContextMenuShowing(ContextMenuEvent event) {

        // Calculate the m/z value of the clicked point
        final double clickedX = event.getX();
        XYPlot plot = chartNode.getChart().getXYPlot();
        Rectangle2D chartArea = chartNode.getRenderingInfo().getPlotInfo().getDataArea();
        RectangleEdge axisEdge = plot.getDomainAxisEdge();
        ValueAxis domainAxis = plot.getDomainAxis();
        final double clickedMz = domainAxis.java2DToValue(clickedX, chartArea, axisEdge);
        final double clickedMzWithShift = Math.abs(clickedMz - mzShift.get());

        // Update the m/z shift menu item
        DecimalFormat mzFormat = MZmineCore.getConfiguration().getMZFormat();
        setToMenuItem.setText("Set to " + mzFormat.format(clickedMz) + " m/z");
        setToMenuItem.setUserData(clickedMz);

        // Update the Show XIC menu item
        showXICMenuItem.setText("Show XIC of " + mzFormat.format(clickedMzWithShift) + " m/z");
        showXICMenuItem.setUserData(clickedMzWithShift);

        // Update the MS/MS menu
        findMSMSMenu.setText("Find MS/MS of " + mzFormat.format(clickedMzWithShift) + " m/z");
        final ObservableList<MenuItem> msmsItems = findMSMSMenu.getItems();
        msmsItems.clear();
        MZmineProject project = MZmineCore.getCurrentProject();
        for (RawDataFile file : project.getRawDataFiles()) {
            scans: for (MsScan scan : file.getScans()) {
                if (scan.getMsFunction().getMsLevel() == 1)
                    continue;
                for (IsolationInfo isolation : scan.getIsolations()) {
                    if (!isolation.getIsolationMzRange().contains(clickedMzWithShift))
                        continue;
                    String menuLabel = MsScanUtils.createSingleLineMsScanDescription(scan, isolation);
                    MenuItem msmsItem = new MenuItem(menuLabel);
                    msmsItem.setOnAction(e -> MsSpectrumPlotModule.showNewSpectrumWindow(scan));
                    msmsItems.add(msmsItem);
                    continue scans;
                }
            }
        }
        if (msmsItems.isEmpty()) {
            MenuItem noneItem = new MenuItem("None");
            noneItem.setDisable(true);
            msmsItems.add(noneItem);
        }

        // Update the Remove... menu
        final ObservableList<MenuItem> rmItems = removeDatasetMenu.getItems();
        rmItems.clear();
        for (MsSpectrumDataSet dataset : datasets) {
            MenuItem msmsItem = new MenuItem(dataset.getName());
            msmsItem.setOnAction(e -> datasets.remove(dataset));
            rmItems.add(msmsItem);
        }
        removeDatasetMenu.setDisable(rmItems.isEmpty());

    }

    public void handleShowXIC(Event event) {
        Double xicMz = (Double) showXICMenuItem.getUserData();
        if (xicMz == null)
            return;

        // Collect all displayed raw data files
        List<RawDataFile> rawDataFiles = new ArrayList<>();
        for (MsSpectrumDataSet dataset : datasets) {
            if (dataset.getSpectrum() instanceof MsScan) {
                MsScan scan = (MsScan) dataset.getSpectrum();
                RawDataFile rawFile = scan.getRawDataFile();
                if (rawFile != null)
                    rawDataFiles.add(rawFile);
            }
        }

        ParameterSet chromatogramParams = MZmineCore.getConfiguration()
                .getModuleParameters(ChromatogramPlotModule.class);
        chromatogramParams.getParameter(ChromatogramPlotParameters.mzRange)
                .setValue(Range.closed(xicMz - 0.005, xicMz + 0.005));
        if (!rawDataFiles.isEmpty()) {
            chromatogramParams.getParameter(ChromatogramPlotParameters.inputFiles)
                    .setValue(new RawDataFilesSelection(rawDataFiles));
        }
        chromatogramParams.showSetupDialog("Show XIC");

    }

    public void handleSetMzShiftTo(Event event) {
        Double newMzShift = (Double) setToMenuItem.getUserData();
        if (newMzShift == null)
            return;
        mzShift.set(newMzShift);
    }

    public void handleSetMzShiftManually(Event event) {
        DecimalFormat mzFormat = MZmineCore.getConfiguration().getMZFormat();
        String newMzShiftString = "0.0";
        Double newMzShift = (Double) setToMenuItem.getUserData();
        if (newMzShift != null)
            newMzShiftString = mzFormat.format(newMzShift);
        TextInputDialog dialog = new TextInputDialog(newMzShiftString);
        dialog.setTitle("m/z shift");
        dialog.setHeaderText("Set m/z shift value");
        Optional<String> result = dialog.showAndWait();
        result.ifPresent(value -> {
            try {
                double newValue = Double.parseDouble(value);
                mzShift.set(newValue);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

    }

    public void handleResetMzShift(Event event) {
        mzShift.set(0.0);
    }

    public void handlePrint(Event event) {
        JFreeChartUtils.printChart(chartNode);
    }

    public void handleNormalizeIntensityScale(Event event) {
        for (MsSpectrumDataSet dataset : datasets) {
            dataset.setIntensityScale(100.0);
        }
    }

    public void handleResetIntensityScale(Event event) {
        for (MsSpectrumDataSet dataset : datasets) {
            dataset.resetIntensityScale();
        }
    }

    public void handleZoomOut(Event event) {
        XYPlot plot = chartNode.getChart().getXYPlot();
        plot.getDomainAxis().setAutoRange(true);
        plot.getRangeAxis().setAutoRange(true);
    }

    public void handleManualZoom(Event event) {
        XYPlot plot = chartNode.getChart().getXYPlot();
        Window parent = chartNode.getScene().getWindow();
        ManualZoomDialog dialog = new ManualZoomDialog(parent, plot);
        dialog.show();
    }

    public void handleCopyImage(Event event) {
        JFreeChartUtils.exportToClipboard(chartNode);
    }

    public void handleExportJPG(Event event) {
        JFreeChartUtils.showSaveDialog(chartNode, ImgFileType.JPG);
    }

    public void handleExportPNG(Event event) {
        JFreeChartUtils.showSaveDialog(chartNode, ImgFileType.PNG);
    }

    public void handleExportPDF(Event event) {
        JFreeChartUtils.showSaveDialog(chartNode, ImgFileType.PDF);
    }

    public void handleExportSVG(Event event) {
        JFreeChartUtils.showSaveDialog(chartNode, ImgFileType.SVG);
    }

    public void handleExportEMF(Event event) {
        JFreeChartUtils.showSaveDialog(chartNode, ImgFileType.EMF);
    }

    public void handleExportEPS(Event event) {
        JFreeChartUtils.showSaveDialog(chartNode, ImgFileType.EPS);
    }

    public void handleCopySpectra(Event event) {
        StringBuilder sb = new StringBuilder();
        for (MsSpectrumDataSet dataset : datasets) {
            MsSpectrum spectrum = dataset.getSpectrum();
            String spectrumString = TxtExportAlgorithm.spectrumToString(spectrum);
            String splash = SplashCalculationAlgorithm.calculateSplash(spectrum);
            sb.append("# ");
            sb.append(dataset.getName());
            sb.append("\n");
            sb.append("# SPLASH ID: ");
            sb.append(splash);
            sb.append("\n");
            sb.append(spectrumString);
            sb.append("\n");
        }
        final Clipboard clipboard = Clipboard.getSystemClipboard();
        final ClipboardContent content = new ClipboardContent();
        content.putString(sb.toString());
        clipboard.setContent(content);
    }

    public void handleCopySplash(Event event) {
        StringBuilder sb = new StringBuilder();
        for (MsSpectrumDataSet dataset : datasets) {
            MsSpectrum spectrum = dataset.getSpectrum();
            String splash = SplashCalculationAlgorithm.calculateSplash(spectrum);
            sb.append(dataset.getName());
            sb.append(" SPLASH ID: ");
            sb.append(splash);
            sb.append("\n");
        }
        final Clipboard clipboard = Clipboard.getSystemClipboard();
        final ClipboardContent content = new ClipboardContent();
        content.putString(sb.toString());
        clipboard.setContent(content);
    }

    public void handleExportMzML(Event event) {

        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Export to mzML");
        fileChooser.getExtensionFilters().add(new ExtensionFilter("mzML", "*.mzML"));

        // Remember last directory
        if (lastSaveDirectory != null && lastSaveDirectory.isDirectory())
            fileChooser.setInitialDirectory(lastSaveDirectory);

        // Show the file chooser
        File file = fileChooser.showSaveDialog(chartNode.getScene().getWindow());

        // If nothing was chosen, quit
        if (file == null)
            return;

        // Save the last open directory
        lastSaveDirectory = file.getParentFile();

        final List<MsSpectrum> spectra = new ArrayList<>();
        for (MsSpectrumDataSet dataset : datasets) {
            spectra.add(dataset.getSpectrum());
        }

        // Do the export in a new thread
        final File finalFile = file;

        new Thread(() -> {
            try {
                // Create a temporary raw data file
                DataPointStore tmpStore = DataPointStoreFactory.getMemoryDataStore();
                RawDataFile tmpRawFile = MSDKObjectBuilder.getRawDataFile("Exported spectra", null,
                        FileType.UNKNOWN, tmpStore);
                int scanNum = 1;
                for (MsSpectrumDataSet dataset : datasets) {
                    MsSpectrum spectrum = dataset.getSpectrum();
                    MsScan newScan;
                    if (spectrum instanceof MsScan) {
                        newScan = MsScanUtil.clone(tmpStore, (MsScan) spectrum, true);
                    } else {
                        MsFunction msf = MSDKObjectBuilder.getMsFunction(MsFunction.DEFAULT_MS_FUNCTION_NAME);
                        newScan = MSDKObjectBuilder.getMsScan(tmpStore, scanNum, msf);
                    }
                    tmpRawFile.addScan(newScan);
                }
                MzMLFileExportMethod exporter = new MzMLFileExportMethod(tmpRawFile, finalFile);
                exporter.execute();
                tmpRawFile.dispose();
            } catch (Exception e) {
                MZmineGUI.displayMessage("Unable to export: " + e.getMessage());
                e.printStackTrace();
            }
        }).start();

    }

    public void handleExportMGF(Event event) {

        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Export to MGF");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Mascot Generic Format", "*.mgf"));

        // Remember last directory
        if (lastSaveDirectory != null && lastSaveDirectory.isDirectory())
            fileChooser.setInitialDirectory(lastSaveDirectory);

        // Show the file chooser
        File file = fileChooser.showSaveDialog(chartNode.getScene().getWindow());

        // If nothing was chosen, quit
        if (file == null)
            return;

        // Save the last open directory
        lastSaveDirectory = file.getParentFile();

        final List<MsSpectrum> spectra = new ArrayList<>();
        for (MsSpectrumDataSet dataset : datasets) {
            spectra.add(dataset.getSpectrum());
        }

        // Do the export in a new thread
        final File finalFile = file;
        new Thread(() -> {
            try {
                MgfFileExportMethod mgfEx = new MgfFileExportMethod(spectra, finalFile);
                mgfEx.execute();
            } catch (Exception e) {
                MZmineGUI.displayMessage("Unable to export: " + e.getMessage());
                e.printStackTrace();
            }
        }).start();
    }

    public void handleExportMSP(Event event) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Export to MSP");
        fileChooser.getExtensionFilters().add(new ExtensionFilter("NIST MSP format", "*.msp"));

        // Remember last directory
        if (lastSaveDirectory != null && lastSaveDirectory.isDirectory())
            fileChooser.setInitialDirectory(lastSaveDirectory);

        // Show the file chooser
        File file = fileChooser.showSaveDialog(chartNode.getScene().getWindow());

        // If nothing was chosen, quit
        if (file == null)
            return;

        // Save the last open directory
        lastSaveDirectory = file.getParentFile();

        final List<MsSpectrum> spectra = new ArrayList<>();
        for (MsSpectrumDataSet dataset : datasets) {
            spectra.add(dataset.getSpectrum());
        }

        // Do the export in a new thread
        final File finalFile = file;
        new Thread(() -> {
            try {
                MspExportAlgorithm.exportSpectra(finalFile, spectra);
            } catch (Exception e) {
                MZmineGUI.displayMessage("Unable to export: " + e.getMessage());
                e.printStackTrace();
            }
        }).start();
    }

    public void handleExportTXT(Event event) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Export to TXT");
        fileChooser.getExtensionFilters().add(new ExtensionFilter("TXT", "*.txt"));

        // Remember last directory
        if (lastSaveDirectory != null && lastSaveDirectory.isDirectory())
            fileChooser.setInitialDirectory(lastSaveDirectory);

        // Show the file chooser
        File file = fileChooser.showSaveDialog(chartNode.getScene().getWindow());

        // If nothing was chosen, quit
        if (file == null)
            return;

        // Save the last open directory
        lastSaveDirectory = file.getParentFile();

        final List<MsSpectrum> spectra = new ArrayList<>();
        for (MsSpectrumDataSet dataset : datasets) {
            spectra.add(dataset.getSpectrum());
        }

        // Do the export in a new thread
        final File finalFile = file;
        new Thread(() -> {
            try {
                TxtExportAlgorithm.exportSpectra(finalFile, spectra);
            } catch (Exception e) {
                MZmineGUI.displayMessage("Unable to export: " + e.getMessage());
                e.printStackTrace();
            }
        }).start();
    }

}