nl.ru.ai.projects.parrot.biomav.editor.BehaviorEditor.java Source code

Java tutorial

Introduction

Here is the source code for nl.ru.ai.projects.parrot.biomav.editor.BehaviorEditor.java

Source

/*
This file is part of the BioMAV project.
    
The BioMAV project 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.
    
The BioMAV project 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 The BioMAV project. If not, see <http://www.gnu.org/licenses/>.
*/
package nl.ru.ai.projects.parrot.biomav.editor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.collections15.Factory;
import org.apache.commons.collections15.Predicate;
import org.apache.commons.collections15.Transformer;

import edu.uci.ics.jung.algorithms.layout.FRLayout2;
import edu.uci.ics.jung.graph.DelegateForest;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedOrderedSparseMultigraph;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.SparseMultigraph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.EditingGraphMousePlugin;
import edu.uci.ics.jung.visualization.control.GraphMouseListener;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.PickingGraphMousePlugin;
import edu.uci.ics.jung.visualization.control.PluggableGraphMouse;
import edu.uci.ics.jung.visualization.control.ViewTranslatingGraphMousePlugin;
import edu.uci.ics.jung.visualization.renderers.DefaultVertexLabelRenderer;
import edu.uci.ics.jung.visualization.renderers.GradientVertexRenderer;
import edu.uci.ics.jung.visualization.renderers.VertexLabelAsShapeRenderer;
import edu.uci.ics.jung.visualization.util.PredicatedParallelEdgeIndexFunction;

/**
 * Editor component that allows editing a finite state machine. The
 * component is a JUNG-based graph editor that can directly manipulate
 * behavior graphs of the finite state machine that controls the drone.  
 * 
 * @author Paul Konstantin Gerke
 *
 */
public class BehaviorEditor extends JPanel {
    private static final long serialVersionUID = 690046335487721939L;

    private DirectedOrderedSparseMultigraph<BehaviorVertex, TransitionEdge> graph = new DirectedOrderedSparseMultigraph<BehaviorVertex, TransitionEdge>();

    private VisualizationViewer<BehaviorVertex, TransitionEdge> graphViewer = new VisualizationViewer<BehaviorVertex, TransitionEdge>(
            new FRLayout2<BehaviorVertex, TransitionEdge>(graph));

    private PluggableGraphMouse graphMouse = new PluggableGraphMouse();
    private EditingGraphMousePlugin<BehaviorVertex, TransitionEdge> graphMouseEditPlugin = new EditingGraphMousePlugin<BehaviorVertex, TransitionEdge>(
            InputEvent.CTRL_MASK, new Factory<BehaviorVertex>() {
                @Override
                public BehaviorVertex create() {
                    BehaviorVertex vertex = new BehaviorVertex();
                    vertex.addBehaviorVertexListener(new BehaviorVertexListener() {
                        @Override
                        public void behaviorVertexActivityChanged(BehaviorVertex vertex) {
                            SwingUtilities.invokeLater(new Runnable() {
                                @Override
                                public void run() {
                                    graphViewer.repaint();
                                }
                            });
                        }
                    });
                    return vertex;
                }
            }, new Factory<TransitionEdge>() {
                @Override
                public TransitionEdge create() {
                    return new TransitionEdge();
                }
            });
    private ViewTranslatingGraphMousePlugin graphMouseTranslatePlugin = new ViewTranslatingGraphMousePlugin(
            MouseEvent.BUTTON3_MASK);
    private PickingGraphMousePlugin<BehaviorVertex, TransitionEdge> graphMousePickPlugin = new PickingGraphMousePlugin<BehaviorVertex, TransitionEdge>();

    private JPanel pcInterfacePanel = new JPanel();
    private JPanel pcInterfacePanelContents = new JPanel();
    private ParameterControlInterface selectedPCInterface = null;

    private void setNewSelectedParameterControlInterface(ParameterControlInterface pcInterface) {
        pcInterfacePanelContents.removeAll();
        selectedPCInterface = null;

        if (pcInterface != null) {
            selectedPCInterface = pcInterface;
            final ParameterControlInterface fpcInterface = pcInterface;

            String[] parameterNames = pcInterface.getParameterNames();
            ParameterControlInterface.ParameterTypes[] parameterTypes = pcInterface.getParameterTypes();

            for (int i = 0; i < parameterTypes.length; i++) {
                JLabel label = new JLabel(parameterNames[i]);
                pcInterfacePanelContents.add(label);

                final int index = i;
                switch (parameterTypes[i]) {
                case OPTIONS:
                    final JComboBox optionComboBox = new JComboBox(pcInterface.getParameterOptions(i));
                    optionComboBox.setEditable(false);
                    optionComboBox.setSelectedItem(pcInterface.getParameterValue(i));

                    optionComboBox.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            fpcInterface.setParameterValue(index, optionComboBox.getSelectedItem());
                            repaint();
                        }
                    });

                    pcInterfacePanelContents.add(optionComboBox);

                    break;
                }
            }
        }

        pcInterfacePanel.validate();
    }

    public BehaviorEditor() {
        ///////// Graph stuff
        graphViewer.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
            }

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_DELETE) {
                    for (TransitionEdge edge : graphViewer.getPickedEdgeState().getPicked()) {
                        graph.removeEdge(edge);
                    }
                    for (BehaviorVertex vertex : graphViewer.getPickedVertexState().getPicked()) {
                        graph.removeVertex(vertex);
                    }
                    e.consume();
                    repaint();
                }
            }
        });

        graphViewer.setBackground(Color.GRAY);

        graphViewer.setGraphMouse(graphMouse);
        graphMouse.add(graphMouseEditPlugin);
        graphMouse.add(graphMouseTranslatePlugin);
        graphMouse.add(graphMousePickPlugin);

        // Set label renderer
        VertexLabelAsShapeRenderer<BehaviorVertex, TransitionEdge> renderer = new VertexLabelAsShapeRenderer<BehaviorVertex, TransitionEdge>(
                graphViewer.getRenderContext());
        graphViewer.getRenderContext().setVertexShapeTransformer(renderer);
        graphViewer.getRenderer().setVertexLabelRenderer(renderer);

        // Set label contents
        graphViewer.getRenderContext().setVertexLabelTransformer(new Transformer<BehaviorVertex, String>() {
            @Override
            public String transform(BehaviorVertex v) {
                return v.getSelectedBehavior();
            }
        });
        graphViewer.getRenderContext().setEdgeLabelTransformer(new Transformer<TransitionEdge, String>() {
            @Override
            public String transform(TransitionEdge e) {
                return e.getTransition();
            }
        });

        // Set fonts
        graphViewer.getRenderContext().setVertexFontTransformer(new Transformer<BehaviorVertex, Font>() {
            @Override
            public Font transform(BehaviorVertex v) {
                return new Font(graphViewer.getFont().getName(), graphViewer.getFont().getStyle(), 20);
            }
        });
        graphViewer.getRenderContext().setEdgeFontTransformer(new Transformer<TransitionEdge, Font>() {
            @Override
            public Font transform(TransitionEdge arg0) {
                return new Font(graphViewer.getFont().getName(), graphViewer.getFont().getStyle(), 16);
            }
        });

        // Fill color dependent on vertex activity
        graphViewer.getRenderContext().setVertexFillPaintTransformer(new Transformer<BehaviorVertex, Paint>() {
            @Override
            public Paint transform(BehaviorVertex vertex) {
                return vertex.isActive() ? Color.ORANGE : Color.RED;
            }
        });

        graphViewer.getPickedVertexState().addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                BehaviorVertex vertex = (BehaviorVertex) e.getItem();
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    setNewSelectedParameterControlInterface(vertex);
                }
                if (e.getStateChange() == ItemEvent.DESELECTED) {
                    if (vertex == selectedPCInterface) {
                        setNewSelectedParameterControlInterface(null);
                    }
                }
            }
        });
        graphViewer.getPickedEdgeState().addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                TransitionEdge edge = (TransitionEdge) e.getItem();
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    setNewSelectedParameterControlInterface(edge);
                }
                if (e.getStateChange() == ItemEvent.DESELECTED) {
                    if (edge == selectedPCInterface) {
                        setNewSelectedParameterControlInterface(null);
                    }
                }
            }
        });

        this.addComponentListener(new ComponentListener() {
            @Override
            public void componentShown(ComponentEvent e) {
            }

            @Override
            public void componentResized(ComponentEvent e) {
                graphViewer.getGraphLayout().setSize(graphViewer.getSize());
            }

            @Override
            public void componentMoved(ComponentEvent e) {
            }

            @Override
            public void componentHidden(ComponentEvent e) {
            }
        });

        ///////////// Side panel (parameter control)
        pcInterfacePanel.setPreferredSize(new Dimension(200, 0));
        pcInterfacePanel.setLayout(new BorderLayout());

        pcInterfacePanelContents.setLayout(new GridLayout(0, 2, 0, 5));
        pcInterfacePanel.add(pcInterfacePanelContents, BorderLayout.NORTH);

        ///////////// [this]

        setLayout(new BorderLayout(10, 10));

        add(graphViewer, BorderLayout.CENTER);
        add(pcInterfacePanel, BorderLayout.EAST);
    }

    public DirectedGraph<BehaviorVertex, TransitionEdge> getGraph() {
        return graph;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame mainFrame = new JFrame("Behavior Editor Test");

                BehaviorEditor be = new BehaviorEditor();
                mainFrame.add(be);

                mainFrame.pack();
                mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                mainFrame.setVisible(true);
            }
        });
    }
}