Package ch.rakudave.jnetmap.view.components

Source Code of ch.rakudave.jnetmap.view.components.TabPanel$TabComponent

package ch.rakudave.jnetmap.view.components;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.lang.reflect.Constructor;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import ch.rakudave.jnetmap.controller.Controller;
import ch.rakudave.jnetmap.controller.command.Command;
import ch.rakudave.jnetmap.model.Connection;
import ch.rakudave.jnetmap.model.Map;
import ch.rakudave.jnetmap.model.MapEvent;
import ch.rakudave.jnetmap.model.MapListener;
import ch.rakudave.jnetmap.model.device.Device;
import ch.rakudave.jnetmap.model.factories.ConnectionFactory;
import ch.rakudave.jnetmap.model.factories.DeviceFactory;
import ch.rakudave.jnetmap.util.Icons;
import ch.rakudave.jnetmap.util.Lang;
import ch.rakudave.jnetmap.util.logging.Logger;
import ch.rakudave.jnetmap.view.jung.EdgeTransformers;
import ch.rakudave.jnetmap.view.jung.MapGraphMouse;
import ch.rakudave.jnetmap.view.jung.VertexTransformers;
import edu.uci.ics.jung.algorithms.layout.CircleLayout;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.ISOMLayout;
import edu.uci.ics.jung.algorithms.layout.KKLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.SpringLayout2;
import edu.uci.ics.jung.algorithms.layout.StaticLayout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.GraphMouseListener;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.layout.LayoutTransition;
import edu.uci.ics.jung.visualization.util.Animator;

/**
* Defines a tab-component that contains and draws a map.
* Tabs feature a close-button similar to Firefox.
* @author rakudave
*/
@SuppressWarnings("serial")
public class TabPanel extends JTabbedPane implements ChangeListener, GraphMouseListener<Device> {
  private TabPanel _this = this; // parent-reference for inner classes
  private Frame owner;
  private List<GraphMouseListener<Device>> graphListeners;
  private static TabComponent currentTab;
  private JButton plusButton;
  private static ScalingControl scaler;
 
  public TabPanel(int tabPlacement, int tabLayoutPolicy, Frame owner) {
    super(tabPlacement, tabLayoutPolicy);
    this.owner = owner;
    graphListeners = new LinkedList<GraphMouseListener<Device>>();
    scaler = new CrossoverScalingControl();
    addTab("+", null, new WelcomeScreen());
    createPlusButton();
    //GraphMouse
    ToolBar.getInstance().add("map.pick", getPickingModeSetter());
    ToolBar.getInstance().add("map.edit", getEditingModeSetter());
    ToolBar.getInstance().add("map.transform", getTransformingModeSetter());
    //Zoom
    ToolBar.getInstance().add("map.zoomin", getZoomPlus());
    ToolBar.getInstance().add("map.zoomout", getZoomMinus());
   
    addChangeListener(this);
  }
 
  @Override
  public void stateChanged(ChangeEvent e) {
    Object o = getSelectedComponent();
    if (o instanceof TabComponent) {
      currentTab = (TabComponent) o;
      Controller.setCurrentMap(currentTab.map);
    }
  }

  private void closeTab(String tabTitle) {
    int tabIndex = getTabIndex(tabTitle);
    TabComponent tc = (TabComponent) getComponentAt(tabIndex);
    if (!Controller.close(tc.map)) return;
    removeTabAt(tabIndex);
  }
 
  private void createPlusButton() {
    plusButton = new JButton(Icons.get("add"));
    plusButton.setContentAreaFilled(false);
    plusButton.setBorder(BorderFactory.createEmptyBorder());
    plusButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        openTab(new Map());
      }
    });
    setTabComponentAt(0, plusButton);
  }

  private int getTabIndex(String tabTitle) {
    for (int i = 0; i < getTabCount()-1; i++) {
      if (tabTitle.equals(getTabComponentAt(i).getName()))
        return i;
    }
    return -1;
  }
 
  public void openTab(Map map) {
    int tabCount = getTabCount()-1;
    final VisualizationViewer<Device, Connection> vv =  new VisualizationViewer<Device, Connection>(map.getGraphLayout());
    map.addMapListener(new MapListener() {
      @Override
      public void mapChanged(MapEvent e) {
        vv.repaint();
      }
    });
    MapGraphMouse egm = new MapGraphMouse(owner, vv.getRenderContext(), new DeviceFactory(), new ConnectionFactory());
      egm.setMode(ModalGraphMouse.Mode.PICKING);
    vv.setGraphMouse(egm);
    vv.setBackground(Color.white);
    vv.addGraphMouseListener(this);
    vv.getRenderer().getVertexLabelRenderer().setPosition(edu.uci.ics.jung.visualization.renderers.Renderer.VertexLabel.Position.S);
    RenderContext<Device, Connection> rc = vv.getRenderContext();
    rc.setVertexIconTransformer(VertexTransformers.iconTransformer(vv.getPickedVertexState()));
    rc.setVertexShapeTransformer(VertexTransformers.shapeTransformer());
    rc.setVertexLabelTransformer(new ToStringLabeller<Device>());
    vv.setVertexToolTipTransformer(VertexTransformers.tooltipTransformer());
    rc.setEdgeStrokeTransformer(EdgeTransformers.strokeTransformer());
    rc.setEdgeDrawPaintTransformer(EdgeTransformers.paintTransformer(vv.getPickedEdgeState()));
    insertTab(map.getFileName(), null, new TabComponent(map, egm, vv), map.getFilePath(), tabCount);
    setTabComponentAt(tabCount, new ClosableTabHeader(map.getFileName(), map.getFilePath()));
    setSelectedIndex(tabCount);
  }
 
  public void addGraphListener(GraphMouseListener<Device> l) {
    graphListeners.add(l);
  }
 
  public void removeGraphListener(GraphMouseListener<Device> l) {
    graphListeners.remove(l);
  }
 
  @Override
  public void graphClicked(Device v, MouseEvent me) {
    for (GraphMouseListener<Device> l : graphListeners) {
      try {
        l.graphClicked(v, me);
      } catch (Exception e) {
        Logger.error("Unable to notify graphListener", e);
      }
    }
  }

  @Override
  public void graphPressed(Device v, MouseEvent me) {
    for (GraphMouseListener<Device> l : graphListeners) {
      try {
        l.graphPressed(v, me);
      } catch (Exception e) {
        Logger.error("Unable to notify graphListener", e);
      }
    }
  }

  @Override
  public void graphReleased(Device v, MouseEvent me) {
    for (GraphMouseListener<Device> l : graphListeners) {
      try {
        l.graphReleased(v, me);
      } catch (Exception e) {
        Logger.error("Unable to notify graphListener", e);
      }
    }
  }
 
  public static Action getPickingModeSetter() {
    return new AbstractAction(Lang.getNoHTML("map.pick"), Icons.get("cursor_pick")) {
      @Override
      public void actionPerformed(ActionEvent e) {
        if (currentTab != null)
          currentTab.mouse.setMode(ModalGraphMouse.Mode.PICKING);
      }
    };
  }

  public static Action getEditingModeSetter() {
    return new AbstractAction(Lang.getNoHTML("map.edit"), Icons.get("cursor_edit")) {
      @Override
      public void actionPerformed(ActionEvent e) {
        if (currentTab != null)
          currentTab.mouse.setMode(ModalGraphMouse.Mode.EDITING);
      }
    };
  }
 
  public static Action getTransformingModeSetter() {
    return new AbstractAction(Lang.getNoHTML("map.transform"), Icons.get("cursor_move")) {
      @Override
      public void actionPerformed(ActionEvent e) {
        if (currentTab != null)
          currentTab.mouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
      }
    };
  }
 
  public static Action getZoomPlus() {
    return new AbstractAction(Lang.getNoHTML("map.zoomin"), Icons.get("zoom_in")) {
      @Override
      public void actionPerformed(ActionEvent e) {
        if (currentTab != null)
          scaler.scale(currentTab.vv, 1.5f, currentTab.vv.getCenter());
      }
    };
  }
 
  public static Action getZoomMinus() {
    return new AbstractAction(Lang.getNoHTML("map.zoomout"), Icons.get("zoom_out")) {
      @Override
      public void actionPerformed(ActionEvent e) {
        if (currentTab != null)
          scaler.scale(currentTab.vv, 1/1.5f, currentTab.vv.getCenter());
      }
    };
  }
 
  // TODO how to set root of a tree???
  /*public static Action getTest() {
    return new AbstractAction(Lang.get("test"), Icons.get("add")) {
      @Override
      public void actionPerformed(ActionEvent e) {
        MinimumSpanningForest2<Device, Connection> prim =
              new MinimumSpanningForest2<Device, Connection>(currentTab.map,
                  new DelegateForest<Device, Connection>(),
                  DelegateTree.<Device, Connection>getFactory(), null);
        currentTab.vv.setGraphLayout(new TreeLayout<Device, Connection>(prim.getForest()));
      }
    };
  }*/
 
 
  @SuppressWarnings({ "unchecked", "rawtypes" })
  public static List<Action> getLayoutTransformers() {
    final LinkedList<Class> layouts = new LinkedList<Class>() {{
      add(CircleLayout.class);
      add(FRLayout.class);
      add(ISOMLayout.class);
      add(KKLayout.class);
      add(SpringLayout2.class);
      add(StaticLayout.class);
    }};
    return new LinkedList<Action>() {{
      for (final Class c : layoutsadd(new AbstractAction(c.getSimpleName()) {
        @Override
        public void actionPerformed(ActionEvent e) {
          setLayout(c);
        }
      });
    }};
  }
 
  @SuppressWarnings({ "unchecked", "rawtypes" })
  public static void setLayout(Class<Layout<Device, Connection>> layout) {
    if (currentTab == null) return;
    final Map map = currentTab.map;
    final VisualizationViewer<Device, Connection> vv = currentTab.vv;
    final Layout<Device, Connection> oldLayout = map.getGraphLayout();
    try {
      Class<? extends Layout<Device, Connection>> layoutC =  (Class<? extends Layout<Device, Connection>>) layout;
          Constructor constructor = layoutC.getConstructor(new Class[] {Graph.class});
          Object o = constructor.newInstance(map);
          final Layout<Device, Connection> newLayout = (Layout<Device, Connection>) o;
          newLayout.setInitializer(vv.getGraphLayout());
          newLayout.setSize(vv.getSize());
      map.getHistory().execute(new Command() {
        @Override
        public Object undo() {
          map.setLayout(oldLayout);
          new Animator(new LayoutTransition<Device, Connection>(vv, newLayout, oldLayout)).start();
          vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
          vv.repaint();
          return null;
        }
       
        @Override
        public Object redo() {
          map.setLayout(newLayout);
          new Animator(new LayoutTransition<Device, Connection>(vv,  oldLayout, newLayout)).start();
          vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
          vv.repaint();
          return null;
        }
      });
    } catch (Exception e) {
      Logger.error("Unable to set new layout "+layout.getSimpleName(), e);
    }
  }
 
  /**
   * "Struct" to keep track of and easily retrieve the Objects corresponding to the displayed Map
   * @author rakudave
   */
  public class TabComponent extends GraphZoomScrollPane {
    Map map;
    MapGraphMouse mouse;
    VisualizationViewer<Device, Connection> vv;

    public TabComponent(Map map, MapGraphMouse mouse, VisualizationViewer<Device, Connection> vv) {
      super(vv);
      this.map = map;
      this.mouse = mouse;
      this.vv = vv;
    }
   
  }
 
  /**
   * Tab-component that may be closed by clicking the "x" located at the right,
   * similar to the way Firefox does it. It also sports an icon and the usual title and tooltip.
   * @author rakudave
   */
  private class ClosableTabHeader extends JPanel {
    private static final long serialVersionUID = -8130758834224431426L;
    private JButton label, close;
   
    public ClosableTabHeader(String title, String path) {
      super(new BorderLayout());
      setName(path + "///" + Math.random()); // UID
      setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
      setBackground(new Color(0, 0, 0, 0));
      label = new JButton(title, Icons.get("jnetmap_small")) {{
        setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 10));
        setContentAreaFilled(false);
        setFocusable(false);
      }};
      label.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          setSelectedIndex(getTabIndex(getName()));
        }
      });
      close = new JButton(Icons.get("close")) {{
        setPreferredSize(new Dimension(16, 16));
        setContentAreaFilled(false);
        setFocusable(false);
      }};
      close.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          _this.closeTab(getName());
        }
      });
      add(label, BorderLayout.CENTER);
      add(close, BorderLayout.EAST);
      setToolTipText(path);
    }
   
    @SuppressWarnings("unused")
    public void setLabel(String text) {
      label.setText(text);
    }
   
    public void setToolTipText(String text) {
      super.setToolTipText(text);
      label.setToolTipText(text);
    }
  }
 
  public static TabComponent getCurrentTab() {
    return currentTab;
  }
}
TOP

Related Classes of ch.rakudave.jnetmap.view.components.TabPanel$TabComponent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.