/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.desktop.tools; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JToggleButton; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.gephi.graph.api.Node; import org.gephi.tools.spi.MouseClickEventListener; import org.gephi.tools.spi.NodeClickEventListener; import org.gephi.tools.spi.NodePressingEventListener; import org.gephi.tools.spi.Tool; import org.gephi.tools.api.ToolController; import org.gephi.tools.spi.NodePressAndDraggingEventListener; import org.gephi.tools.spi.ToolEventListener; import org.gephi.tools.spi.ToolSelectionType; import org.gephi.tools.spi.ToolUI; import org.gephi.visualization.VizController; import org.gephi.visualization.apiimpl.VizEvent; import org.gephi.visualization.apiimpl.VizEvent.Type; import org.gephi.visualization.apiimpl.VizEventListener; import org.gephi.visualization.api.selection.SelectionManager; import org.openide.util.Lookup; import org.openide.util.lookup.ServiceProvider; /** * * @author Mathieu Bastian */ @ServiceProvider(service = ToolController.class) public class DesktopToolController implements ToolController { private Toolbar toolbar; private boolean unselectTool; //Architecture private Tool[] tools; private PropertiesBar propertiesBar; //Current tool private Tool currentTool; private ToolEventHandler[] currentHandlers; public DesktopToolController() { //Init tools tools = Lookup.getDefault().lookupAll(Tool.class).toArray(new Tool[0]); } public void select(Tool tool) { unselect(); if (tool == null) { return; } //Connect events ArrayList<ToolEventHandler> handlers = new ArrayList<ToolEventHandler>(); for (ToolEventListener toolListener : tool.getListeners()) { if (toolListener instanceof NodeClickEventListener) { NodeClickEventHandler h = new NodeClickEventHandler(toolListener); h.select(); handlers.add(h); } else if (toolListener instanceof NodePressingEventListener) { NodePressingEventHandler h = new NodePressingEventHandler(toolListener); h.select(); handlers.add(h); } else if (toolListener instanceof MouseClickEventListener) { MouseClickEventHandler h = new MouseClickEventHandler(toolListener); h.select(); handlers.add(h); } else if (toolListener instanceof NodePressAndDraggingEventListener) { NodePressAndDraggingEventHandler h = new NodePressAndDraggingEventHandler(toolListener); h.select(); handlers.add(h); } else { throw new RuntimeException("The ToolEventListener " + toolListener.getClass().getSimpleName() + " cannot be recognized"); } } currentHandlers = handlers.toArray(new ToolEventHandler[0]); switch (tool.getSelectionType()) { case NONE: VizController.getInstance().getSelectionManager().disableSelection(); break; case SELECTION: VizController.getInstance().getSelectionManager().blockSelection(true); VizController.getInstance().getSelectionManager().setDraggingEnable(false); break; case SELECTION_AND_DRAGGING: VizController.getInstance().getSelectionManager().blockSelection(true); VizController.getInstance().getSelectionManager().setDraggingEnable(true); break; } currentTool = tool; unselectTool = currentTool.select(); if (unselectTool) { toolbar.clearSelection(); unselect(); } } public void unselect() { if (currentTool != null) { //Disconnect events for (ToolEventHandler handler : currentHandlers) { handler.unselect(); } currentTool.unselect(); currentHandlers = null; currentTool = null; if (propertiesBar != null) { propertiesBar.unselect(); } } } public JComponent getToolbar() { //Get tools ui HashMap<ToolUI, Tool> toolMap = new HashMap<ToolUI, Tool>(); List<ToolUI> toolsUI = new ArrayList<ToolUI>(); for (Tool tool : tools) { ToolUI ui = tool.getUI(); if (ui != null) { toolsUI.add(ui); toolMap.put(ui, tool); } } //Sort by priority Collections.sort(toolsUI, new Comparator() { public int compare(Object o1, Object o2) { Integer p1 = ((ToolUI) o1).getPosition(); Integer p2 = ((ToolUI) o2).getPosition(); return p1.compareTo(p2); } }); //Create toolbar final Toolbar toolbar = new Toolbar(); for (final ToolUI toolUI : toolsUI) { final Tool tool = toolMap.get(toolUI); JToggleButton btn; if (toolUI.getIcon() != null) { btn = new JToggleButton(toolUI.getIcon()); } else { btn = new JToggleButton(new ImageIcon(getClass().getResource("/org/gephi/desktop/tools/tool.png"))); } btn.setToolTipText(toolUI.getName() + " - " + toolUI.getDescription()); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //Let the user unselect a tool (by clicking on it again) without having to select other tool: if (tool == currentTool) { toolbar.clearSelection(); unselect(); } else { select(tool); if (!unselectTool) propertiesBar.select(toolUI.getPropertiesBar(tool)); } } }); toolbar.add(btn); } //SelectionManager events VizController.getInstance().getSelectionManager().addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { SelectionManager selectionManager = VizController.getInstance().getSelectionManager(); if (selectionManager.isRectangleSelection() && currentTool != null) { toolbar.clearSelection(); unselect(); } else if (selectionManager.isSelectionEnabled() && currentTool != null && currentTool.getSelectionType() == ToolSelectionType.NONE) { toolbar.clearSelection(); unselect(); } else if (selectionManager.isDraggingEnabled() && currentTool != null) { toolbar.clearSelection(); unselect(); } } }); this.toolbar = toolbar; return toolbar; } public JComponent getPropertiesBar() { propertiesBar = new PropertiesBar(); return propertiesBar; } //Event handlers classes private static interface ToolEventHandler { public void select(); public void unselect(); } //HANDLERS private static class NodeClickEventHandler implements ToolEventHandler { private NodeClickEventListener toolEventListener; private VizEventListener currentListener; public NodeClickEventHandler(ToolEventListener toolListener) { this.toolEventListener = (NodeClickEventListener) toolListener; } public void select() { currentListener = new VizEventListener() { public void handleEvent(VizEvent event) { toolEventListener.clickNodes((Node[]) event.getData()); } public Type getType() { return VizEvent.Type.NODE_LEFT_CLICK; } }; VizController.getInstance().getVizEventManager().addListener(currentListener); } public void unselect() { VizController.getInstance().getVizEventManager().removeListener(currentListener); currentListener = null; toolEventListener = null; } } private static class NodePressingEventHandler implements ToolEventHandler { private NodePressingEventListener toolEventListener; private VizEventListener[] currentListeners; public NodePressingEventHandler(ToolEventListener toolListener) { this.toolEventListener = (NodePressingEventListener) toolListener; } public void select() { currentListeners = new VizEventListener[2]; currentListeners[0] = new VizEventListener() { public void handleEvent(VizEvent event) { toolEventListener.pressingNodes((Node[]) event.getData()); } public Type getType() { return VizEvent.Type.NODE_LEFT_PRESSING; } }; currentListeners[1] = new VizEventListener() { public void handleEvent(VizEvent event) { toolEventListener.released(); } public Type getType() { return VizEvent.Type.MOUSE_RELEASED; } }; VizController.getInstance().getVizEventManager().addListener(currentListeners); } public void unselect() { VizController.getInstance().getVizEventManager().removeListener(currentListeners); toolEventListener = null; currentListeners = null; } } private static class NodePressAndDraggingEventHandler implements ToolEventHandler { private NodePressAndDraggingEventListener toolEventListener; private VizEventListener[] currentListeners; public NodePressAndDraggingEventHandler(ToolEventListener toolListener) { this.toolEventListener = (NodePressAndDraggingEventListener) toolListener; } public void select() { currentListeners = new VizEventListener[3]; currentListeners[0] = new VizEventListener() { public void handleEvent(VizEvent event) { toolEventListener.pressNodes((Node[]) event.getData()); } public Type getType() { return VizEvent.Type.NODE_LEFT_PRESS; } }; currentListeners[1] = new VizEventListener() { public void handleEvent(VizEvent event) { float[] mouseDrag = (float[]) event.getData(); toolEventListener.drag(mouseDrag[0], mouseDrag[1]); } public Type getType() { return VizEvent.Type.DRAG; } }; currentListeners[2] = new VizEventListener() { public void handleEvent(VizEvent event) { toolEventListener.released(); } public Type getType() { return VizEvent.Type.MOUSE_RELEASED; } }; VizController.getInstance().getVizEventManager().addListener(currentListeners); } public void unselect() { VizController.getInstance().getVizEventManager().removeListener(currentListeners); toolEventListener = null; currentListeners = null; } } private static class MouseClickEventHandler implements ToolEventHandler { private MouseClickEventListener toolEventListener; private VizEventListener currentListener; public MouseClickEventHandler(ToolEventListener toolListener) { this.toolEventListener = (MouseClickEventListener) toolListener; } public void select() { currentListener = new VizEventListener() { public void handleEvent(VizEvent event) { float[] data = (float[]) event.getData(); int[] viewport = new int[]{(int) data[0], (int) data[1]}; float[] threed = new float[]{data[2], data[3]}; toolEventListener.mouseClick(viewport, threed); } public Type getType() { return VizEvent.Type.MOUSE_LEFT_CLICK; } }; VizController.getInstance().getVizEventManager().addListener(currentListener); } public void unselect() { VizController.getInstance().getVizEventManager().removeListener(currentListener); toolEventListener = null; currentListener = null; } } }