All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.limetri.client.mapviewer.nb.jxmap.DrawingController Maven / Gradle / Ivy

There is a newer version: 1.4.4
Show newest version
/**
 * Copyright (C) 2008-2012 AgroSense Foundation.
 *
 * AgroSense 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 3 of the License, or
 * (at your option) any later version.
 *
 * There are special exceptions to the terms and conditions of the GPLv3 as it is applied to
 * this software, see the FLOSS License Exception
 * .
 *
 * AgroSense 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 AgroSense.  If not, see .
 */
package eu.limetri.client.mapviewer.nb.jxmap;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Logger;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JToolBar;

import nl.cloudfarming.eventbus.GuiEvent;
import nl.cloudfarming.eventbus.GuiEventBus;
import nl.cloudfarming.eventbus.GuiEventKey;
import nl.cloudfarming.eventbus.GuiEventListener;

import org.jdesktop.swingx.JXPanel;
import org.openide.nodes.Node;
import org.openide.nodes.NodeEvent;
import org.openide.nodes.NodeListener;
import org.openide.nodes.NodeMemberEvent;
import org.openide.nodes.NodeReorderEvent;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;

import eu.limetri.client.mapviewer.api.Layer;
import eu.limetri.client.mapviewer.api.SingleObjectLayer;
import eu.limetri.client.mapviewer.api.event.GeoEvent;
import eu.limetri.client.mapviewer.swing.JXMapViewer;
import eu.limetri.client.mapviewer.swing.jxmap.map.AreaMeasurementContext;
import eu.limetri.client.mapviewer.swing.jxmap.map.DrawingContext;
import eu.limetri.client.mapviewer.swing.jxmap.map.LengthMeasurementContext;
import eu.limetri.client.mapviewer.swing.jxmap.map.PolygonDrawingContext;
import eu.limetri.client.mapviewer.swing.jxmap.map.SplitPolygonDrawingContext;

/**
 * Controller to control the drawing and splitting of polygons
 *
 * @author johan
 */
@NbBundle.Messages({
    "# {0} - context description", "app_log_start_drawing_context=Started {0}",
    "# {0} - context description", "app_log_stop_drawing_context=Finished {0}",})
public class DrawingController {

    private static final Logger LOGGER = Logger.getLogger(DrawingController.class.getCanonicalName());
    private EditLayerEventListener editLayerEventListener = new EditLayerEventListener();
    private SplitLayerEventListener splitLayerEventListener = new SplitLayerEventListener();
    private MeasureLengthEventListener measureLengthEventListener = new MeasureLengthEventListener();
    private MeasureAreaEventListener measureAreaEventListener = new MeasureAreaEventListener();
    private final DrawingPanel drawingPanel;
    private final JXPanel toolsPanel;
    private DrawingContext context;
    private RootNodeListener rootNodeListener = new RootNodeListener();

    public DrawingController(JXMapViewer mapPanel) {
        this.drawingPanel = new DrawingPanel(mapPanel);
        this.toolsPanel = new JXPanel();
        toolsPanel.setOpaque(false);
        toolsPanel.setLayout(new BorderLayout());
        drawingPanel.addNodeListener(rootNodeListener);

        // listen for edit requests:
        GuiEventBus.addListener(editLayerEventListener);
        GuiEventBus.addListener(splitLayerEventListener);
        
        //measure
        GuiEventBus.addListener(measureLengthEventListener);
        GuiEventBus.addListener(measureAreaEventListener);
    }

    private void createGeometry(SingleObjectLayer layer) {
        startContext(new PolygonDrawingContext(layer, drawingPanel.getMapViewer()));
    }

    private void editGeometry(SingleObjectLayer layer) {
        // TODO
    }

    private void splitGeometry(Node node) {
        startContext(new SplitPolygonDrawingContext(node, drawingPanel.getMapViewer()));
    }

    /**
     * Get the drawing panel this controller controls
     *
     * @return
     */
    public DrawingPanel getDrawingPanel() {
        return drawingPanel;
    }

    /**
     * Get the tools panel this controller controls
     *
     * @return
     */
    public JXPanel getToolsPanel() {
        return toolsPanel;
    }

    private void startContext(DrawingContext context) {
        // check preconditions:
        if (!context.canStart()) {
            context.cancel();
            return; 
        }
        
        this.context = context;
        
        // setup toolbar, initial widgets
        drawingPanel.addContext(context);

        JToolBar tools = new JToolBar(JToolBar.VERTICAL);
        for (Action a : context.getActions()) {
            tools.add(a);
        }

        tools.addSeparator();
        tools.add(new FinishAction(context, this));
        tools.add(new CancelAction(context, this));
        tools.setFloatable(false);
        toolsPanel.add(tools, BorderLayout.EAST);
        toolsPanel.getParent().validate();

        GeoEvent.getProducer().triggerEvent(GeoEvent.TOOLS_PANEL, Boolean.TRUE);
        LOGGER.info(Bundle.app_log_start_drawing_context(context.getDescription()));
    }

    private void stopContext(DrawingContext context) {
        // remove toolbar & widgets:
        drawingPanel.removeContext(context);
        toolsPanel.removeAll();
        toolsPanel.getParent().repaint();
        toolsPanel.getParent().validate();
        
        LOGGER.info(Bundle.app_log_stop_drawing_context(context.getDescription()));
        GeoEvent.getProducer().triggerEvent(GeoEvent.TOOLS_PANEL, Boolean.FALSE);
        this.context = null;
    }

    private class EditLayerEventListener implements GuiEventListener {

        @Override
        public void onEvent(GuiEvent event) {
            if (!isBusy()) {
                SingleObjectLayer layer = event.getContent();
                if (layer.hasGeometry()) {
                    editGeometry(layer);
                } else {
                    createGeometry(layer);
                }
            } else {
                LOGGER.warning("Edit layer requested while editing");
            }
        }

        @Override
        public boolean listensTo(GuiEventKey guiEventKey) {
            return GeoEvent.EDIT_LAYER.equals(guiEventKey);
        }

        @Override
        public String getModuleName() {
            return Module.MODULE_NAME;
        }
    }

    private class SplitLayerEventListener implements GuiEventListener {

        @Override
        public void onEvent(GuiEvent event) {
            if (!isBusy()) {
                splitGeometry(event.getContent());
            } else {
                LOGGER.warning("Split layer requested while editing");
            }
        }

        @Override
        public boolean listensTo(GuiEventKey guiEventKey) {
            return GeoEvent.SPLIT_LAYER.equals(guiEventKey);
        }

        @Override
        public String getModuleName() {
            return Module.MODULE_NAME;
        }
    }

    /**
     * Checks if busy by checking if the context is null
     *
     * @return
     */
    private boolean isBusy() {
        return context != null;
    }

    /**
     * listener for changes in nodes in the explorer manager
     */
    private class RootNodeListener implements NodeListener {

        private ChildrenListener childrenDestroyedListener = new ChildrenListener();

        @Override
        public void childrenAdded(NodeMemberEvent ev) {
            if (ev.getDelta().length == 1 && !isBusy()) {
                Node node = ev.getDelta()[0];
                SingleObjectLayer layer = node.getLookup().lookup(SingleObjectLayer.class);
                if (layer != null && !layer.hasGeometry()) {
                    createGeometry(layer);
                    
                }
            }
            for(Node node : ev.getDelta()){
                node.addNodeListener(childrenDestroyedListener);
            }
        }

        @Override
        public void childrenRemoved(NodeMemberEvent ev) {
            nodesRemoved(ev.getDelta());
        }

        @Override
        public void childrenReordered(NodeReorderEvent ev) {
        }

        @Override
        public void nodeDestroyed(NodeEvent ev) {
            nodesRemoved(ev.getNode());
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
        }

        public void nodesRemoved(Node... nodes) {
            if (isBusy()) {
                for (Node node : nodes) {
                    Layer layer = node.getLookup().lookup(Layer.class);
                    if (layer != null && layer.equals(context.getLayer())) {
                        context.cancel();
                        stopContext(context);
                    }
                }
            }
        }

        /**
         * Listens to deletion of children of the root node
         */
        private class ChildrenListener implements NodeListener {

            @Override
            public void childrenAdded(NodeMemberEvent ev) {
            }

            @Override
            public void childrenRemoved(NodeMemberEvent ev) {
            }

            @Override
            public void childrenReordered(NodeReorderEvent ev) {
            }

            @Override
            public void nodeDestroyed(NodeEvent ev) {
                nodesRemoved(ev.getNode());
            }

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
            }
        }
    }

    //
    // default toolbar actions:
    //
    @NbBundle.Messages({
        "drawing_finish_action_name=Finish",
        "drawing_finish_action_tooltip=Finish",
        "drawing_finish_action_icon=eu/limetri/client/mapviewer/swing/jxmap/icons/accept24.png"})
    private class FinishAction extends AbstractAction {

        private final DrawingContext context;
        private final DrawingController controller;

        public FinishAction(final DrawingContext context, DrawingController controller) {
            this.context = context;
            this.controller = controller;
            putValue(SHORT_DESCRIPTION, Bundle.drawing_finish_action_tooltip());
            putValue(LARGE_ICON_KEY, ImageUtilities.loadImageIcon(Bundle.drawing_finish_action_icon(), true));
            setEnabled(context.canFinish());
            context.addPropertyChangeListener(new PropertyChangeListener() {

                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    setEnabled(context.canFinish());
                }
            });
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (context.finish()) {
                controller.stopContext(context);
            }
        }
    }

    @NbBundle.Messages({
        "drawing_cancel_action_name=Cancel",
        "drawing_cancel_action_tooltip=Cancel",
        "drawing_cancel_action_icon=eu/limetri/client/mapviewer/swing/jxmap/icons/cancel24.png"})
    private class CancelAction extends AbstractAction {

        private DrawingContext context;
        private DrawingController controller;

        public CancelAction(DrawingContext context, DrawingController controller) {
            this.context = context;
            this.controller = controller;
            putValue(SHORT_DESCRIPTION, Bundle.drawing_cancel_action_tooltip());
            putValue(LARGE_ICON_KEY, ImageUtilities.loadImageIcon(Bundle.drawing_cancel_action_icon(), true));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            context.cancel();
            controller.stopContext(context);
        }
    }
    
    private class MeasureLengthEventListener implements GuiEventListener {
        
        @Override
        public void onEvent(GuiEvent event) {
            if (!isBusy()) {
                measureLength();
            } else {
                LOGGER.warning("Length measurement requested while editing");
            }
        }

        @Override
        public boolean listensTo(GuiEventKey guiEventKey) {
            return GeoEvent.MEASURE_LENGTH.equals(guiEventKey);
        }

        @Override
        public String getModuleName() {
            return Module.MODULE_NAME;
        }
        
    }
    
    private class MeasureAreaEventListener implements GuiEventListener {
        
        @Override
        public void onEvent(GuiEvent event) {
            if (!isBusy()) {
                measureArea();
            } else {
                LOGGER.warning("Area measurement requested while editing");
            }
        }

        @Override
        public boolean listensTo(GuiEventKey guiEventKey) {
            return GeoEvent.MEASURE_AREA.equals(guiEventKey);
        }

        @Override
        public String getModuleName() {
            return Module.MODULE_NAME;
        }
        
    }
    
    private void measureLength() {
        startContext(new LengthMeasurementContext(drawingPanel.getMapViewer()));
    }
    
    private void measureArea() {
        startContext(new AreaMeasurementContext(drawingPanel.getMapViewer()));
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy