net.sf.mzmine.chartbasics.gestures.ChartGestureHandler.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.mzmine.chartbasics.gestures.ChartGestureHandler.java

Source

/*
 * Copyright 2006-2018 The MZmine 2 Development Team
 * 
 * This file is part of MZmine 2.
 * 
 * MZmine 2 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 2 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 2; if not,
 * write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 * USA
 */

package net.sf.mzmine.chartbasics.gestures;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.TitleEntity;
import org.jfree.data.Range;
import net.sf.mzmine.chartbasics.ChartLogics;
import net.sf.mzmine.chartbasics.gestures.ChartGesture.Button;
import net.sf.mzmine.chartbasics.gestures.ChartGesture.Entity;
import net.sf.mzmine.chartbasics.gestures.ChartGesture.Event;
import net.sf.mzmine.chartbasics.gestures.ChartGesture.Key;
import net.sf.mzmine.chartbasics.gestures.ChartGestureDragDiffHandler.Orientation;
import net.sf.mzmine.chartbasics.gestures.interf.GestureHandlerFactory;
import net.sf.mzmine.chartbasics.gestures.standard.DragGestureHandlerDef;
import net.sf.mzmine.chartbasics.gestures.standard.GestureHandlerDef;
import net.sf.mzmine.chartbasics.gui.wrapper.MouseEventWrapper;
import net.sf.mzmine.chartbasics.listener.ZoomHistory;

/**
 * The handler processes {@link ChartGestureEvent}s in a {@link Consumer}. Pre-defined handlers and
 * drag-difference handlers can be generated. It also provides a static list of standard gesture
 * handler definitions.
 * 
 * @author Robin Schmid (robinschmid@uni-muenster.de)
 */
public class ChartGestureHandler {
    /**
     * Some standard handlers
     */
    public enum Handler {
        DEBUG, // Prints out the gesture
        PREVIOUS_ZOOM_HISTORY, // Jump back in the zoom history
        NEXT_ZOOM_HISTORY, // Jump forward in the zoom history
        TITLE_REMOVER, // Remove titles (setVisible false)
        AUTO_ZOOM_AXIS, // Auto zoom axis
        AUTO_ZOOM_OPPOSITE_AXIS, // Auto zoom opposite axis (domain<->range axis)
        SCROLL_AXIS, // Scroll an axis while retaining the zoom
        SCROLL_AXIS_AND_AUTO_ZOOM, // Scroll an axis and auto zoom the other
        ZOOM_AXIS_INCLUDE_ZERO, // Zoom an axis while holding the lowerBound
        ZOOM_AXIS_CENTER; // Zoom and axis centered to the start gesture

        @Override
        public String toString() {
            return super.toString().replaceAll("_", " ");
        }
    }

    /**
     * Some DragDiff standard handlers
     */
    public enum DragHandler {
        AUTO_ZOOM_AXIS, // Auto zoom axis
        AUTO_ZOOM_OPPOSITE_AXIS, // Auto zoom opposite axis (domain<->range axis)
        SCROLL_AXIS, // Scroll an axis while retaining the zoom
        SCROLL_AXIS_AND_AUTO_ZOOM, // Scroll an axis and auto zoom the other
        ZOOM_AXIS_INCLUDE_ZERO, // Zoom an axis while holding the lowerBound
        ZOOM_AXIS_CENTER; // Zoom and axis centered to the start gesture

        @Override
        public String toString() {
            return super.toString().replaceAll("_", " ");
        }
    }

    // static list of standard chartgestures as GestureHandlerFactories
    // initialise + getter
    private static List<GestureHandlerFactory> standardGestures = null;

    // non static section
    private ChartGesture gesture;
    private Consumer<ChartGestureEvent> handler;

    public ChartGestureHandler(ChartGesture gesture, Consumer<ChartGestureEvent> handler) {
        this.gesture = gesture;
        this.handler = handler;
    }

    public ChartGestureHandler(ChartGesture gesture) {
        this.gesture = gesture;
    }

    public void setConsumer(Consumer<ChartGestureEvent> handler) {
        this.handler = handler;
    }

    public void accept(ChartGestureEvent e) {
        if (handler != null)
            handler.accept(e);
    }

    public ChartGesture getGesture() {
        return gesture;
    }

    public Consumer<ChartGestureEvent> getHandler() {
        return handler;
    }

    /**
     * The drag diff handler listens for PRESSED, DRAGGED and RELEASED events and is called for every
     * range difference between two events. is a range difference between two drag events
     * 
     * @param handler A list of DragHandlers (predefined consumers)
     * @param key A list of Key filters which are connected to the handler list
     * @param entity The Entity filter
     * @param button The Button filter
     * @param orient Orientation of drag events (Horizontal or Vertical)
     * @param param Parameters for specific handlers
     */
    public static ChartGestureHandler createDragDiffHandler(DragHandler[] handler, Key[] key, Entity entity,
            Button button, Orientation orient, Object[] param) {
        Consumer<ChartGestureDragDiffEvent>[] consumer = new Consumer[handler.length];
        // create all consumers for all keys
        try {
            for (int i = 0; i < consumer.length; i++) {
                consumer[i] = createDragDiffConsumer(handler[i], param);
            }
            return new ChartGestureDragDiffHandler(entity, button, key, consumer);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Creates a predefined consumer for drag diff events
     * 
     * @param handler The predefined consumer
     * @param param Parameters for specific handlers
     * @return
     * @throws Exception
     */
    public static Consumer<ChartGestureDragDiffEvent> createDragDiffConsumer(DragHandler handler, Object[] param)
            throws Exception {
        switch (handler) {
        case SCROLL_AXIS:
            return e -> {
                ValueAxis axis = e.getAxis();
                if (axis != null)
                    ChartLogics.offsetAxisAbsolute(axis, e.getDiff());
            };
        case SCROLL_AXIS_AND_AUTO_ZOOM:
            return de -> {
                ValueAxis axis = de.getAxis();
                if (axis != null) {
                    ChartLogics.offsetAxisAbsolute(axis, de.getDiff());
                    if (de.getEntity().equals(Entity.DOMAIN_AXIS))
                        de.getChartWrapper().autoRangeAxis();
                    else
                        de.getChartWrapper().autoDomainAxis();
                }
            };
        case AUTO_ZOOM_AXIS:
            return de -> {
                ValueAxis axis = de.getAxis();
                if (axis != null)
                    ChartLogics.autoAxis(axis);
            };
        case AUTO_ZOOM_OPPOSITE_AXIS:
            return de -> {
                ValueAxis axis = de.getAxis();
                if (axis != null) {
                    if (de.getEntity().equals(Entity.DOMAIN_AXIS))
                        de.getChartWrapper().autoRangeAxis();
                    else
                        de.getChartWrapper().autoDomainAxis();
                }
            };
        case ZOOM_AXIS_INCLUDE_ZERO:
            return de -> {
                ValueAxis axis = de.getAxis();
                if (axis != null) {
                    double diff = de.getDiff() / axis.getRange().getLength() * 4;
                    ChartLogics.zoomAxis(axis, diff, true);
                }
            };
        case ZOOM_AXIS_CENTER:
            return de -> {
                ValueAxis axis = de.getAxis();
                if (axis != null) {
                    double diff = de.getDiff() / axis.getRange().getLength() * 4;
                    ChartLogics.zoomAxis(axis, diff, de.getStart());
                }
            };
        default:
            throw new Exception("DragHandler not specified");
        }
    }

    /**
     * Create preset handlers
     * 
     * @param handler
     * @param g
     * @return
     */
    public static ChartGestureHandler createHandler(Handler handler, ChartGesture g) {
        return createHandler(handler, g, null);
    }

    /**
     * Create preset handlers
     * 
     * @param handler
     * @param g
     * @param param Parameters for specific handlers <br>
     * @return
     */
    public static ChartGestureHandler createHandler(Handler handler, final ChartGesture g, Object[] param) {
        Consumer<ChartGestureEvent> newHandler = null;
        switch (handler) {
        case DEBUG:
            newHandler = e -> System.out.println(e.toString());
            break;
        case PREVIOUS_ZOOM_HISTORY:
            newHandler = e -> {
                ZoomHistory h = e.getChartWrapper().getZoomHistory();
                if (h != null) {
                    Range[] range = h.setPreviousPoint();
                    if (range != null && range.length > 0 && range[0] != null) {
                        ValueAxis dom = e.getChart().getXYPlot().getDomainAxis();
                        ValueAxis ran = e.getChart().getXYPlot().getRangeAxis();
                        ChartLogics.setZoomAxis(dom, range[0]);
                        ChartLogics.setZoomAxis(ran, range[1]);
                    }
                }
            };
            break;
        case NEXT_ZOOM_HISTORY:
            newHandler = e -> {
                ZoomHistory h = e.getChartWrapper().getZoomHistory();
                if (h != null) {
                    Range[] range = h.setNextPoint();
                    if (range != null && range.length > 0 && range[0] != null) {
                        ValueAxis dom = e.getChart().getXYPlot().getDomainAxis();
                        ValueAxis ran = e.getChart().getXYPlot().getRangeAxis();
                        ChartLogics.setZoomAxis(dom, range[0]);
                        ChartLogics.setZoomAxis(ran, range[1]);
                    }
                }
            };
            break;
        case TITLE_REMOVER:
            newHandler = e -> {
                if (e.getEntity() instanceof TitleEntity) {
                    TitleEntity te = (TitleEntity) e.getEntity();
                    te.getTitle().setVisible(false);
                }
            };
            break;
        case AUTO_ZOOM_AXIS:
            newHandler = e -> {
                ValueAxis a = e.getAxis();
                if (a != null)
                    ChartLogics.autoAxis(a);
            };
            break;
        case AUTO_ZOOM_OPPOSITE_AXIS:
            newHandler = e -> {
                if (e.getGesture().getEntity().equals(Entity.AXIS)) {
                    e.getChartWrapper().autoRangeAxis();
                    e.getChartWrapper().autoDomainAxis();
                } else if (e.getGesture().getEntity().equals(Entity.DOMAIN_AXIS))
                    e.getChartWrapper().autoRangeAxis();
                else
                    e.getChartWrapper().autoDomainAxis();
            };
            break;
        case SCROLL_AXIS:
            newHandler = e -> {
                ValueAxis axis = e.getAxis();
                if (axis != null) {
                    double diff = 0.03;
                    if (e.getMouseEvent().isMouseWheelEvent()) {
                        diff = -0.10 * e.getMouseEvent().getWheelRotation();
                    }
                    ChartLogics.offsetAxis(axis, diff);
                }
            };
            break;
        case SCROLL_AXIS_AND_AUTO_ZOOM:
            newHandler = e -> {
                ValueAxis axis = e.getAxis();
                if (axis != null) {
                    double diff = 0.03;
                    if (e.getMouseEvent().isMouseWheelEvent()) {
                        diff = -0.10 * e.getMouseEvent().getWheelRotation();
                    }
                    ChartLogics.offsetAxis(axis, diff);

                    if (e.getGesture().getEntity().equals(Entity.DOMAIN_AXIS))
                        e.getChartWrapper().autoRangeAxis();
                    else
                        e.getChartWrapper().autoDomainAxis();
                }
            };
            break;
        case ZOOM_AXIS_INCLUDE_ZERO:
            newHandler = e -> {
                ValueAxis axis = e.getAxis();
                if (axis != null) {
                    double diff = 0.05;
                    if (e.getMouseEvent().isMouseWheelEvent()) {
                        diff = -0.10 * e.getMouseEvent().getWheelRotation();
                    }
                    ChartLogics.zoomAxis(axis, diff, true);
                }
            };
            break;
        case ZOOM_AXIS_CENTER:
            newHandler = e -> {
                ValueAxis axis = e.getAxis();
                if (axis != null) {
                    MouseEventWrapper p = e.getMouseEvent();
                    double diff = 0.05;
                    if (e.getMouseEvent().isMouseWheelEvent()) {
                        diff = -0.10 * p.getWheelRotation();
                    }

                    // get data space coordinates
                    Point2D point = e.getCoordinates(p.getX(), p.getY());
                    if (point != null) {
                        // vertical ?
                        Boolean orient = e.isVerticalAxis(axis);
                        if (orient == null)
                            return;
                        else if (orient)
                            ChartLogics.zoomAxis(axis, diff, point.getY());
                        else
                            ChartLogics.zoomAxis(axis, diff, point.getX());
                    }
                }
            };
            break;
        default:
            break;
        }
        if (newHandler == null)
            return null;
        else
            return new ChartGestureHandler(g, newHandler);
    }

    /**
     * A list of standard gestures
     * 
     * @see {@link GestureHandlerDef} {@link DragGestureHandlerDef}
     * @return
     */
    public static List<GestureHandlerFactory> getStandardGestures() {
        if (standardGestures == null)
            initStandardGestures(true, true, true, true, true);
        return standardGestures;
    }

    /**
     * Generates a list of standard chart gesture
     * 
     * @param axisDrag
     * @param axisWheel
     * @param titleRemover
     * @param zoomHistory
     * @param axisAutoRange
     * @return
     */
    public static List<GestureHandlerFactory> initStandardGestures(boolean axisDrag, boolean axisWheel,
            boolean titleRemover, boolean zoomHistory, boolean axisAutoRange) {
        standardGestures = new ArrayList<GestureHandlerFactory>();
        if (axisDrag) {
            // adds multiple gestures to one domain axis drag handler
            // Scroll axis: DRAG mouse over domain axis
            // Scroll + auto zoom: SHIFT + DRAG
            // Zoom axis centered: CTRL + DRAG
            // Zoom + auto zoom range axis: CTRL + SHIFT + DRAG
            standardGestures.add(new DragGestureHandlerDef(
                    new DragHandler[] { DragHandler.SCROLL_AXIS, DragHandler.SCROLL_AXIS_AND_AUTO_ZOOM,
                            DragHandler.ZOOM_AXIS_CENTER, DragHandler.ZOOM_AXIS_CENTER,
                            DragHandler.AUTO_ZOOM_OPPOSITE_AXIS },
                    new Key[] { Key.NONE, Key.SHIFT, Key.CTRL, Key.CTRL_SHIFT, Key.CTRL_SHIFT }, Entity.DOMAIN_AXIS,
                    Button.BUTTON1, null, null));

            // Zoom range axis (include zero): DRAG
            standardGestures.add(new DragGestureHandlerDef(new DragHandler[] { DragHandler.ZOOM_AXIS_INCLUDE_ZERO },
                    new Key[] { Key.ALL }, Entity.RANGE_AXIS, Button.BUTTON1, null, null));
        }
        if (axisWheel) {
            // MOUSE WHEEL on domain axis
            // Scroll axis: WHEEL over domain axis
            // Scroll + auto zoom: SHIFT + WHEEL
            // Zoom axis centered: CTRL + WHEEL
            // Zoom + auto zoom range axis: CTRL + SHIFT + WHEEL
            standardGestures.add(new GestureHandlerDef(Handler.SCROLL_AXIS, Entity.DOMAIN_AXIS,
                    new Event[] { Event.MOUSE_WHEEL }, null, Key.NONE, null));
            standardGestures.add(new GestureHandlerDef(Handler.SCROLL_AXIS_AND_AUTO_ZOOM, Entity.DOMAIN_AXIS,
                    new Event[] { Event.MOUSE_WHEEL }, null, Key.SHIFT, null));
            standardGestures.add(new GestureHandlerDef(Handler.ZOOM_AXIS_CENTER, Entity.DOMAIN_AXIS,
                    new Event[] { Event.MOUSE_WHEEL }, null, Key.CTRL, null));
            standardGestures.add(new GestureHandlerDef(Handler.ZOOM_AXIS_CENTER, Entity.DOMAIN_AXIS,
                    new Event[] { Event.MOUSE_WHEEL }, null, Key.CTRL_SHIFT, null));
            standardGestures.add(new GestureHandlerDef(Handler.AUTO_ZOOM_OPPOSITE_AXIS, Entity.DOMAIN_AXIS,
                    new Event[] { Event.MOUSE_WHEEL }, null, Key.CTRL_SHIFT, null));
            // Zoom range axis (include zero): MOUSE WHEEL
            standardGestures.add(new GestureHandlerDef(Handler.ZOOM_AXIS_INCLUDE_ZERO, Entity.RANGE_AXIS,
                    new Event[] { Event.MOUSE_WHEEL }, null, Key.ALL, null));
        }
        if (zoomHistory) {
            // Previous zoom history: DOUBLE CLICK on plot
            // Next zoom history: CTRL + DOUBLE CLICK on plot
            standardGestures.add(new GestureHandlerDef(Handler.PREVIOUS_ZOOM_HISTORY, Entity.PLOT,
                    new Event[] { Event.DOUBLE_CLICK }, Button.BUTTON1, Key.NONE, null));
            standardGestures.add(new GestureHandlerDef(Handler.NEXT_ZOOM_HISTORY, Entity.PLOT,
                    new Event[] { Event.DOUBLE_CLICK }, Button.BUTTON1, Key.CTRL, null));
        }
        if (titleRemover) {
            // Remove titles, legends: CTRL + CLICK on titles
            standardGestures.add(new GestureHandlerDef(Handler.TITLE_REMOVER, Entity.TITLE,
                    new Event[] { Event.CLICK }, Button.BUTTON1, Key.CTRL, null));
        }
        if (axisAutoRange) {
            // Auto zoom axes: DOUBLE CLICK on axis
            standardGestures.add(new GestureHandlerDef(Handler.AUTO_ZOOM_AXIS, Entity.DOMAIN_AXIS,
                    new Event[] { Event.DOUBLE_CLICK }, Button.BUTTON1, null, null));
            standardGestures.add(new GestureHandlerDef(Handler.AUTO_ZOOM_AXIS, Entity.RANGE_AXIS,
                    new Event[] { Event.DOUBLE_CLICK }, Button.BUTTON1, null, null));
        }
        return standardGestures;
    }
}