edu.caltech.ipac.firefly.commands.MarkerToolCmd.java Source code

Java tutorial

Introduction

Here is the source code for edu.caltech.ipac.firefly.commands.MarkerToolCmd.java

Source

/*
 * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt
 */
package edu.caltech.ipac.firefly.commands;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

import edu.caltech.ipac.firefly.ui.GwtUtil;
import edu.caltech.ipac.firefly.ui.input.InputField;
import edu.caltech.ipac.firefly.ui.input.SimpleInputField;
import edu.caltech.ipac.firefly.ui.input.TextBoxInputField;
import edu.caltech.ipac.firefly.ui.input.ValidationInputField;
import edu.caltech.ipac.firefly.util.BrowserUtil;
import edu.caltech.ipac.firefly.util.WebAssert;
import edu.caltech.ipac.firefly.util.event.Name;
import edu.caltech.ipac.firefly.util.event.WebEvent;
import edu.caltech.ipac.firefly.util.event.WebEventListener;
import edu.caltech.ipac.firefly.visualize.AllPlots;
import edu.caltech.ipac.firefly.visualize.CircularMarker;
import edu.caltech.ipac.firefly.visualize.Marker;
import edu.caltech.ipac.firefly.visualize.MiniPlotWidget;
import edu.caltech.ipac.firefly.visualize.ScreenPt;
import edu.caltech.ipac.firefly.visualize.WebPlot;
import edu.caltech.ipac.firefly.visualize.WebPlotView;
import edu.caltech.ipac.firefly.visualize.draw.DrawObj;
import edu.caltech.ipac.firefly.visualize.draw.DrawingManager;
import edu.caltech.ipac.firefly.visualize.draw.ShapeDataObj;
import edu.caltech.ipac.firefly.visualize.draw.SimpleDataConnection;
import edu.caltech.ipac.firefly.visualize.draw.WebLayerItem;
import edu.caltech.ipac.util.StringUtils;
import edu.caltech.ipac.visualize.plot.WorldPt;

public class MarkerToolCmd extends BaseGroupVisCmd implements WebEventListener/*, PrintableOverlay*/ {

    public enum Mode {
        ADD_MARKER, MOVE, RESIZE, OFF
    }

    public static final String BASE_DRAWER_ID = "MarkerToolID#";
    public static final int EDIT_DISTANCE = BrowserUtil.isTouchInput() ? 20 : 12;
    public static final String _selHelpText = "Tap to create marker";
    public static final String _editHelpText = "Click center and drag to move, click corner and drag to resize";
    public static final String BASE_TITLE = "Marker #";

    public static int mCnt = 0;

    public static final String CommandName = "MarkerTool";
    private HashMap<Marker, MarkerDrawing> _markerMap = new HashMap<Marker, MarkerDrawing>(10);
    private Marker _activeMarker = null;

    private Mode _mode;
    private boolean _mouseDown = false;
    private boolean _doMove = false;
    private final WebPlotView.MouseInfo _mouseInfo = new WebPlotView.MouseInfo(new Mouse(), "Create a marker");
    private final static String _onLabel = "Hide Marker";
    private final static String _offLabel = "Show Marker";
    private final static String _addLabel = "Add Marker";

    public MarkerToolCmd() {
        super(CommandName);
        AllPlots.getInstance().addListener(this);
        changeMode(Mode.OFF);
    }

    //======================================================================
    //------------------ Methods from WebEventListener ------------------
    //======================================================================

    public void eventNotify(WebEvent ev) {
        Name name = ev.getName();
        if (name.equals(Name.FITS_VIEWER_ADDED)) {
            if (_markerMap.size() > 0) {
                addViewer((MiniPlotWidget) ev.getData());
            }
        } else if (name.equals(Name.ALL_FITS_VIEWERS_TEARDOWN)) {
            clearAllViewers();
            changeMode(Mode.OFF);
        }
    }

    //======================================================================
    //------------------ Private / Protected Methods -----------------------
    //======================================================================

    private void addViewer(MiniPlotWidget mpw) {
        for (Map.Entry<Marker, MarkerDrawing> entry : _markerMap.entrySet()) {
            entry.getValue().getDrawMan().addPlotView(mpw.getPlotView());
        }
    }

    private void clearAllViewers() {
        for (Map.Entry<Marker, MarkerDrawing> entry : _markerMap.entrySet()) {
            entry.getValue().getDrawMan().clear();
        }
        _markerMap.clear();

    }

    protected void doExecute() {
        switch (_mode) {
        case ADD_MARKER:
        case RESIZE:
        case MOVE:
            disableSelection();
            changeMode(Mode.OFF);
            //                AlertLayerPopup.setAlert(false);
            break;
        case OFF:
            if (_markerMap.size() == 0)
                changeMode(Mode.ADD_MARKER);
            else
                changeMode(Mode.MOVE);
            setupMouse();
            //                AlertLayerPopup.setAlert(true);
            break;
        default:
            WebAssert.argTst(false, "only support for SelectType of ADD_MARKER, RESIZE or MOVE");
            break;
        }
    }

    @Override
    public boolean hasIcon() {
        return false;
    }

    //    @Override
    //    public Image createCmdImage() {
    //
    //        VisIconCreator ic = VisIconCreator.Creator.getInstance();
    //        String iStr = this.getIconProperty();
    //        if (iStr != null) {
    //
    //            if (iStr.equals(_onIcon)) {
    //                return new Image(ic.getMarkerOn());
    //            } else if (iStr.equals(_offIcon)) {
    //                return new Image(ic.getMarkerOff());
    //            } else if (iStr.equals(CommandName + ".Icon")) {
    //                return new Image(ic.getMarkerOff());
    //            }
    //        }
    //        return null;
    //    }
    //

    private void setupMouse() {
        grabMouse();
        getMiniPlotWidget().hideSelectionBar();
    }

    private void changeMode(Mode newMode) {
        _mode = newMode;
        switch (_mode) {
        case ADD_MARKER:
            createDrawMan();
            setLabel(_onLabel);
            break;
        case MOVE:
            setLabel(_onLabel);
            changeToEditHelp();
            addDrawMan();
            break;
        case RESIZE:
            setLabel(_onLabel);
            changeToEditHelp();
            addDrawMan();
            break;
        case OFF:
            removeDrawMan();
            setLabel(_markerMap.size() > 0 ? _offLabel : _addLabel);
            break;
        default:
            WebAssert.argTst(false, "only support for SelectType of ADD_MARKER, RESIZE or MOVE");
            break;
        }
    }

    private void disableSelection() {
        switch (_mode) {
        case ADD_MARKER:
        case RESIZE:
        case MOVE:
            releaseMouse();
            break;
        case OFF: /* do nothing*/
            break;
        default:
            WebAssert.argTst(false, "only support for SelectType of ADD_MARKER, RESIZE or MOVE");
            break;
        }
    }

    private void setActiveMarker(Marker m) {
        _activeMarker = m;
    }

    private void begin(WebPlotView pv, ScreenPt spt) {
        WebPlot plot = pv.getPrimaryPlot();
        _mouseInfo.setEnableAllPersistent(true);
        _mouseInfo.setEnableAllExclusive(false);

        if (_mode == Mode.ADD_MARKER) {
            _doMove = true;
            changeMode(Mode.MOVE);
            drag(pv, spt);
        } else {
            Marker m = findEditableMarker(plot, spt);
            if (m != null) {
                setActiveMarker(m); // ONLY set _activeMarker if m!=null
                _markerMap.get(m).cancelDeferred();
                _doMove = true;
                if (m.contains(spt, plot)) {
                    changeMode(Mode.MOVE);
                } else {
                    changeMode(Mode.RESIZE);
                }
                drag(pv, spt);
            } else {
                _mouseInfo.setEnableAllExclusive(true);
            }
        }

    }

    private void drag(WebPlotView pv, ScreenPt spt) {
        if (!_doMove)
            return;

        WebPlot plot = pv.getPrimaryPlot();
        _mouseInfo.setEnableAllPersistent(true);
        _mouseInfo.setEnableAllExclusive(false);

        switch (_mode) {
        case ADD_MARKER:
            break;
        case MOVE:
            WorldPt center = plot.getWorldCoords(spt);
            if (center == null)
                return;
            _activeMarker.move(center, plot);
            break;
        case RESIZE:
            _activeMarker.setEndPt(plot.getWorldCoords(spt), plot);
            break;
        default:
            WebAssert.argTst(false, "only support for SelectType of ADD_MARKER or MOVE");
            break;
        }

        updateData(_activeMarker, plot, true);
        _markerMap.get(_activeMarker).getDrawMan().redraw();
    }

    private void end(WebPlotView pv) {
        if (!_doMove)
            return;

        _mouseInfo.setEnableAllPersistent(true);
        _mouseInfo.setEnableAllExclusive(false);
        switch (_mode) {
        case ADD_MARKER:
            releaseMouse();
            break;
        case MOVE:
        case RESIZE:
            _activeMarker.adjustStartEnd(pv.getPrimaryPlot());
            _markerMap.get(_activeMarker).deferDraw(pv.getPrimaryPlot(), _activeMarker);

            //                    updateData(_activeMarker, null);
            //                    _markerMap.get(_activeMarker).getDrawMan().redraw();
            break;
        default:
            WebAssert.argTst(false, "only support for SelectType of ADD_MARKER or MOVE");
            break;
        }
        _doMove = false;
    }

    private Marker findEditableMarker(WebPlot plot, ScreenPt pt) {
        if (plot == null || pt == null)
            return null;

        Marker retval = null;
        List<Marker> centerList = new ArrayList<Marker>(10);
        for (Marker m : _markerMap.keySet()) {
            if (m.contains(pt, plot))
                centerList.add(m);
        }
        int minDist = Integer.MAX_VALUE;
        int dist;
        if (centerList.size() > 0) {
            for (Marker m : centerList) {
                if (_markerMap.get(m).isVisible()) {
                    dist = m.getCenterDistance(pt, plot);
                    if (dist < minDist && dist > -1) {
                        retval = m;
                        minDist = dist;
                    }
                }
            }
        } else {
            Marker candidate = null;
            Marker.MinCorner editCorner = null;
            for (Marker m : _markerMap.keySet()) {
                if (_markerMap.get(m).isVisible()) {
                    Marker.MinCorner minC = m.getMinCornerDistance(pt, plot);
                    if (minC != null && minC.getDistance() < minDist) {
                        candidate = m;
                        minDist = minC.getDistance();
                        editCorner = minC;
                    }
                    if (minDist < EDIT_DISTANCE) {
                        retval = candidate;
                        retval.setEditCorner(editCorner.getCorner(), plot);
                    }
                }
            }

        }
        return retval;

    }

    private void updateAllData() {
        for (Marker m : _markerMap.keySet()) {
            WebPlot p = getPlotView() != null ? getPlotView().getPrimaryPlot() : null;
            updateData(m, getPlotView().getPrimaryPlot(), false);
        }
    }

    private void updateData(Marker m, WebPlot plot, boolean drawHandles) {
        if (m.isReady()) {
            List<DrawObj> data = new ArrayList<DrawObj>(1);
            List<DrawObj> editData = new ArrayList<DrawObj>(1);
            //            ShapeDataObj markerShape= m.getShape().get(0); // main shape
            //            data.add(markerShape);
            //            data.add(ShapeDataObj.makeCircle(m.getStartPt(), m.getEndPt()));

            ShapeDataObj markerShape = ShapeDataObj.makeCircle(m.getStartPt(), m.getEndPt());
            data.add(markerShape);
            if (drawHandles) {
                int size = 5;
                editData.add(ShapeDataObj.makeRectangle(m.getCorner(Marker.Corner.NW, plot), size, size));
                editData.add(ShapeDataObj.makeRectangle(m.getCorner(Marker.Corner.NE, plot), -size, size));
                editData.add(ShapeDataObj.makeRectangle(m.getCorner(Marker.Corner.SW, plot), size, -size));
                editData.add(ShapeDataObj.makeRectangle(m.getCorner(Marker.Corner.SE, plot), -size, -size));
            }
            if (!StringUtils.isEmpty(m.getTitle()) && plot != null) {
                markerShape.setFontName(m.getFont());
                markerShape.setText(SafeHtmlUtils.fromString(m.getTitle()).asString());
                markerShape.setTextLocation(convertTextLoc(m.getTextCorner()));
            }

            _markerMap.get(m).getConnect().setData(data, editData, plot);
        }
    }

    private static ShapeDataObj.TextLocation convertTextLoc(Marker.Corner corner) {
        switch (corner) {
        case NE:
            return ShapeDataObj.TextLocation.CIRCLE_NE;
        case NW:
            return ShapeDataObj.TextLocation.CIRCLE_NW;
        case SE:
            return ShapeDataObj.TextLocation.CIRCLE_SE;
        case SW:
            return ShapeDataObj.TextLocation.CIRCLE_SW;
        }
        return ShapeDataObj.TextLocation.CIRCLE_NE;
    }

    private void grabMouse() {
        List<MiniPlotWidget> mpwList = getAllActivePlots();
        for (MiniPlotWidget mpw : mpwList) {
            mpw.getPlotView().setTouchScrollingEnabled(false);
            mpw.getPlotView().grabMouse(_mouseInfo);
        }
    }

    private void releaseMouse() {
        List<MiniPlotWidget> mpwList = getAllActivePlots();
        for (MiniPlotWidget mpw : mpwList) {
            mpw.getPlotView().setTouchScrollingEnabled(true);
            mpw.getPlotView().releaseMouse(_mouseInfo);
        }
    }

    private void removeDrawMan() {
        DrawingManager drawMan;
        for (MarkerDrawing md : _markerMap.values()) {
            md.saveColor();
            drawMan = md.getDrawMan();
            drawMan.clear();
            for (MiniPlotWidget mpw : getAllActivePlots()) {
                drawMan.removePlotView(mpw.getPlotView());
            }
            md.getConnect().clearData();
        }
    }

    private void createDrawMan() {
        //        _activeMarker = new RectangleMarker(80, 50);//new CircularMarker(20);
        _activeMarker = new CircularMarker(20);
        _markerMap.put(_activeMarker, new MarkerDrawing());

        WebPlotView pv = getPlotView();
        if (pv != null && pv.getPrimaryPlot() != null) {
            WebPlot plot = pv.getPrimaryPlot();
            WorldPt center = pv.findCurrentCenterWorldPoint();
            _activeMarker.move(center, plot);
            updateData(_activeMarker, plot, true);
            _markerMap.get(_activeMarker).getDrawMan().redraw();
        }

    }

    private void changeToEditHelp() {
        boolean first = true;
        for (MarkerDrawing md : _markerMap.values()) {
            md.getDrawMan().setHelp(_editHelpText);
            if (first) {
                md.getDrawMan().showMouseHelp(getPlotView());
                first = false;
            }
        }

    }

    private void addDrawMan() {
        DrawingManager drawMan;
        updateAllData();
        for (MarkerDrawing md : _markerMap.values()) {
            drawMan = md.getDrawMan();
            for (MiniPlotWidget mpw : AllPlots.getInstance().getAll(true)) {
                drawMan.addPlotView(mpw.getPlotView());
            }
            md.restoreColor();
            drawMan.redraw();
        }
    }

    private void removeMarker(String id) {
        Marker marker = null;
        MarkerDrawing drawing = null;
        for (Map.Entry<Marker, MarkerDrawing> entry : _markerMap.entrySet()) {
            if (entry.getValue().getID().equals(id)) {
                marker = entry.getKey();
                drawing = entry.getValue();
                break;
            }
        }
        if (marker != null) {
            _markerMap.remove(marker);
            drawing.freeResources();
        }
    }

    private Marker findMarker(String id) {
        Marker retval = null;
        for (Map.Entry<Marker, MarkerDrawing> entry : _markerMap.entrySet()) {
            if (entry.getValue().getID().equals(id)) {
                retval = entry.getKey();
                break;
            }
        }
        return retval;
    }

    //======================================================================
    //------------------ Inner classes-----------------------
    //======================================================================

    private class Mouse extends WebPlotView.DefMouseAll {

        @Override
        public void onMouseDown(WebPlotView pv, ScreenPt spt, MouseDownEvent ev) {
            _mouseDown = true;
            begin(pv, spt);
        }

        @Override
        public void onMouseMove(WebPlotView pv, ScreenPt spt, MouseMoveEvent ev) {
            if (_mouseDown)
                drag(pv, spt);
        }

        @Override
        public void onMouseUp(WebPlotView pv, ScreenPt spt) {
            if (_mouseDown) {
                _mouseDown = false;
                end(pv);
            }
        }

        @Override
        public void onTouchStart(WebPlotView pv, ScreenPt spt, TouchStartEvent ev) {
            _mouseDown = true;
            begin(pv, spt);
        }

        @Override
        public void onTouchMove(WebPlotView pv, ScreenPt spt, TouchMoveEvent ev) {
            if (_mouseDown)
                drag(pv, spt);
        }

        @Override
        public void onTouchEnd(WebPlotView pv) {
            if (_mouseDown) {
                _mouseDown = false;
                end(pv);
            }
        }
    }

    private class MarkerDrawing {
        private MarkerConnect connect;
        private DrawingManager drawMan;
        private DeferredDrawer _dd = new DeferredDrawer();
        private String _color;
        private String _id;

        private MarkerDrawing() {
            mCnt++;
            _id = BASE_DRAWER_ID + mCnt;
            connect = new MarkerConnect(BASE_TITLE + mCnt);
            if (!WebLayerItem.hasUICreator(_id)) {
                WebLayerItem.addUICreator(_id, new MarkerUICreator());
            }
            drawMan = new DrawingManager(_id, connect);
            drawMan.setHelp(_selHelpText);
            drawMan.showMouseHelp(getPlotView());
            List<MiniPlotWidget> mpwList = getAllActivePlots();
            for (MiniPlotWidget mpw : mpwList)
                drawMan.addPlotView(mpw.getPlotView());
        }

        public void freeResources() {
            List<MiniPlotWidget> mpwList = AllPlots.getInstance().getAll();
            for (MiniPlotWidget mpw : mpwList)
                drawMan.removePlotView(mpw.getPlotView());
            connect = null;
            drawMan = null;
        }

        public MarkerConnect getConnect() {
            return connect;
        }

        public DrawingManager getDrawMan() {
            return drawMan;
        }

        public void saveColor() {
            _color = drawMan.getActiveColor();
        }

        public void restoreColor() {
            if (_color != null)
                drawMan.setDefaultColor(_color);
        }

        public String getID() {
            return _id;
        }

        public void deferDraw(WebPlot plot, Marker marker) {
            _dd.cancel();
            _dd.draw(plot, marker, drawMan);
        }

        public void cancelDeferred() {
            _dd.cancel();
        }

        public boolean isVisible() {
            return drawMan != null ? drawMan.isVisibleGuess() : false;
        }
    }

    private class MarkerConnect extends SimpleDataConnection {
        private List<DrawObj> _mainData;
        private List<DrawObj> _editData;
        private WebPlot _editingPlot = null;

        MarkerConnect(String title) {
            super(title, _editHelpText);
        }

        @Override
        public List<DrawObj> getData(boolean rebuild, WebPlot plot) {
            List<DrawObj> retval;
            if (plot == null)
                return _mainData;

            if (plot != _editingPlot) {
                retval = _mainData;
            } else {
                if (_mainData != null) {
                    retval = new ArrayList<DrawObj>(_mainData.size() + _editData.size());
                    retval.addAll(_mainData);
                    retval.addAll(_editData);
                } else {
                    retval = Collections.emptyList();
                }
            }
            return retval;
        }

        public void setData(List<DrawObj> mainData, List<DrawObj> editData, WebPlot editingPlot) {
            _mainData = mainData;
            _editData = editData;
            _editingPlot = editingPlot;
        }

        public void clearData() {
            _mainData = null;
            _editData = null;
            _editingPlot = null;
        }

        @Override
        public boolean getHasPerPlotData() {
            return true;
        }
    }

    private class MarkerUICreator extends WebLayerItem.UICreator {

        private MarkerUICreator() {
            super(true, true);
        }

        public Widget makeExtraUI(final WebLayerItem item) {
            Label add = GwtUtil.makeLinkButton("Add marker", "Add a marker", new ClickHandler() {
                public void onClick(ClickEvent event) {
                    changeMode(Mode.ADD_MARKER);
                }
            });
            //            Label remove = GwtUtil.makeLinkButton("remove", "remove marker", new ClickHandler() {
            //                public void onClick(ClickEvent event) {
            //                    removeMarker(item.getID());
            //                    if (_markerMap.size()==0) changeMode(Mode.OFF);
            //                }
            //            });
            //            StringFieldDef fd= new StringFieldDef("MarkerToolCmd.title");

            HorizontalPanel hp = new HorizontalPanel();
            final SimpleInputField field = SimpleInputField.createByProp("MarkerTool.title");
            field.setInternalCellSpacing(1);
            final InputField tIf = ((ValidationInputField) field.getField()).getIF();
            final String originalTitle = item.getTitle();
            TextBox tb = ((TextBoxInputField) tIf).getTextBox();

            Marker marker = findMarker(item.getID());
            if (marker != null) {
                String t = marker.getTitle();
                field.setValue(t);
                if (!StringUtils.isEmpty(t))
                    item.setTitle(t);
            }

            final SimpleInputField corner = SimpleInputField.createByProp("MarkerTool.corner");
            corner.setInternalCellSpacing(1);

            GwtUtil.setStyle(add, "padding", "5px 0 0 11px");

            //            hp.add(remove);
            hp.add(field);
            hp.add(corner);
            hp.add(add);
            //            hp.setSpacing(4);

            tb.addKeyPressHandler(new KeyPressHandler() {
                public void onKeyPress(KeyPressEvent event) {
                    DeferredCommand.addCommand(new Command() {
                        public void execute() {
                            updateTitle(item, tIf.getValue(), corner.getValue(), item.getID(), originalTitle);
                        }
                    });
                }
            });
            corner.getField().addValueChangeHandler(new ValueChangeHandler<String>() {
                public void onValueChange(ValueChangeEvent<String> ev) {
                    updateTitle(item, tIf.getValue(), corner.getValue(), item.getID(), originalTitle);
                }
            });

            return hp;
        }

        private void updateTitle(WebLayerItem item, String title, String cStr, String id, String originalTitle) {

            Marker.Corner corner;
            try {
                corner = Enum.valueOf(Marker.Corner.class, cStr);
            } catch (Exception e) {
                corner = Marker.Corner.SE;
            }

            item.setTitle(StringUtils.isEmpty(title) ? originalTitle : title);
            Marker marker = findMarker(id);
            setActiveMarker(marker);
            marker.setTitle(title);
            marker.setTitleCorner(corner);
            WebPlotView pv = getPlotView();
            updateData(_activeMarker, pv.getPrimaryPlot(), false);
            _markerMap.get(_activeMarker).getDrawMan().redraw();
        }

        public void delete(WebLayerItem item) {
            removeMarker(item.getID());
            if (_markerMap.size() == 0)
                changeMode(Mode.OFF);
        }
    }

    private class DeferredDrawer extends Timer {
        private DrawingManager drawer;
        private WebPlot plot;

        private void draw(WebPlot plot, Marker marker, DrawingManager drawer) {
            this.drawer = drawer;
            this.plot = plot;
            updateData(_activeMarker, plot, true);
            drawer.redraw();
            schedule(2000);
        }

        @Override
        public void run() {
            updateData(_activeMarker, plot, false);
            drawer.redraw();
        }
    }

}