/*FreeMind - A Program for creating and viewing Mindmaps *Copyright (C) 2000-2006 Joerg Mueller, Daniel Polansky, Christian Foltin, Dimitri Polivaev and others. * *See COPYING for Details * *This program 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 2 *of the License, or (at your option) any later version. * *This program 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 this program; if not, write to the Free Software *Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Created on 28.03.2004 * */ package accessories.plugins; import java.awt.EventQueue; import java.util.Iterator; import java.util.Map; import java.util.Vector; import javax.swing.Action; import javax.swing.JMenuItem; import freemind.controller.Controller; import freemind.controller.MenuItemEnabledListener; import freemind.extensions.HookRegistration; import freemind.modes.MindMap; import freemind.modes.MindMapNode; import freemind.modes.ModeController; import freemind.modes.ModeController.NodeSelectionListener; import freemind.modes.mindmapmode.MindMapController; import freemind.modes.mindmapmode.actions.NodeHookAction; import freemind.modes.mindmapmode.hooks.MindMapNodeHookAdapter; import freemind.view.MapModule; import freemind.view.mindmapview.NodeView; /** * @author foltin * */ public class NodeHistory extends MindMapNodeHookAdapter { /** Of NodeHolder */ private static Vector sNodeVector = new Vector(); private static int sCurrentPosition = 0; private static boolean sPreventRegistration = false; private static class NodeHolder { public String mNodeId; public String mMapModuleName; public NodeHolder(MindMapNode pNode, MindMapController pMindMapController) { mNodeId = pNode.getObjectId(pMindMapController); MapModule mapModule = pMindMapController.getMapModule(); if (mapModule == null) { throw new IllegalArgumentException( "MapModule not present to controller " + pMindMapController); } mMapModuleName = mapModule.toString(); } /** @return null, if node not found. */ public MindMapNode getNode(Controller pController) { ModeController modeController = getModeController(pController); if (modeController != null) { return modeController.getNodeFromID(mNodeId); } return null; } private ModeController getModeController(Controller pController) { ModeController modeController = null; MapModule mapModule = getMapModule(pController); if (mapModule != null) { modeController = mapModule.getModeController(); } return modeController; } private MapModule getMapModule(Controller pController) { MapModule mapModule = null; Map mapModules = pController.getMapModuleManager().getMapModules(); for (Iterator iter = mapModules.keySet().iterator(); iter.hasNext();) { String mapModuleName = (String) iter.next(); if (mapModuleName != null && mapModuleName.equals(mMapModuleName)) { mapModule = (MapModule) mapModules.get(mapModuleName); break; } } return mapModule; } public boolean isIdentical(MindMapNode pNode, MindMapController pMindMapController) { String id = pNode.getObjectId(pMindMapController); MapModule mapModule = pMindMapController.getMapModule(); if (mapModule != null) { return id.equals(mNodeId); } return false; } } public static class Registration implements HookRegistration, NodeSelectionListener, MenuItemEnabledListener { private final MindMapController controller; private final MindMap mMap; private final java.util.logging.Logger logger; public Registration(ModeController controller, MindMap map) { this.controller = (MindMapController) controller; mMap = map; logger = controller.getFrame().getLogger(this.getClass().getName()); } public void register() { controller.registerNodeSelectionListener(this, false); } public void deRegister() { controller.deregisterNodeSelectionListener(this); } public void onLostFocusNode(NodeView pNode) { } public void onFocusNode(NodeView pNode) { /******************************************************************* * don't denote positions, if somebody navigates through them. * */ if (!NodeHistory.sPreventRegistration) { // no duplicates: if (sCurrentPosition > 0 && ((NodeHolder) sNodeVector.get(sCurrentPosition - 1)) .isIdentical(pNode.getModel(), controller)) { // logger.info("Avoid duplicate " + pNode + " at " + // sCurrentPosition); return; } if (sCurrentPosition != sNodeVector.size()) { /*********************************************************** * * we change the selected in the middle of our vector. * Thus we remove all the coming nodes: **********************************************************/ for (int i = sNodeVector.size() - 1; i >= sCurrentPosition; --i) { sNodeVector.removeElementAt(i); } } // logger.info("Adding " + pNode + " at " + sCurrentPosition); sNodeVector.add(new NodeHolder(pNode.getModel(), controller)); sCurrentPosition++; // only the last 100 nodes while (sNodeVector.size() > 100) { sNodeVector.removeElementAt(0); sCurrentPosition--; } } } public void onSaveNode(MindMapNode pNode) { } public void onUpdateNodeHook(MindMapNode pNode) { } public boolean isEnabled(JMenuItem pItem, Action pAction) { String hookName = ((NodeHookAction) pAction).getHookName(); if ("accessories/plugins/NodeHistoryBack.properties" .equals(hookName)) { // back is only enabled if there are already some nodes to go // back ;-) return sCurrentPosition > 1; } else { return sCurrentPosition < sNodeVector.size(); } } /* (non-Javadoc) * @see freemind.modes.ModeController.NodeSelectionListener#onSelectionChange(freemind.modes.MindMapNode, boolean) */ public void onSelectionChange(NodeView pNode, boolean pIsSelected) { } } /** * */ public NodeHistory() { super(); } public void invoke(MindMapNode node) { super.invoke(node); final Registration registration = (Registration) getPluginBaseClass(); final MindMapController modeController = getMindMapController(); String direction = getResourceString("direction"); // logger.info("Direction: " + direction); if ("back".equals(direction)) { if (sCurrentPosition > 1) { --sCurrentPosition; } else { return; } } else { if (sCurrentPosition < sNodeVector.size()) { ++sCurrentPosition; } else { return; } } if (sCurrentPosition == 0) return; // printVector(); NodeHolder nodeHolder = (NodeHolder) sNodeVector .get(sCurrentPosition - 1); final Controller mainController = getController().getController(); final MindMapNode toBeSelected = (nodeHolder).getNode(mainController); boolean changeModule = false; MapModule newModule = null; if (nodeHolder.getModeController(mainController) != getMindMapController()) { changeModule = true; newModule = nodeHolder.getMapModule(mainController); if (newModule == null) { // the map was apparently closed, we try with the next node. invoke(node); return; } } final boolean fChangeModule = changeModule; final MapModule fNewModule = newModule; logger.finest("Selecting " + toBeSelected + " at pos " + sCurrentPosition); sPreventRegistration = true; /*********************************************************************** * as the selection is restored after invoke, we make this trick to * change it. **********************************************************************/ EventQueue.invokeLater(new Runnable() { public void run() { ModeController c = modeController; if (fChangeModule) { boolean res = mainController.getMapModuleManager() .changeToMapModule(fNewModule.toString()); if (!res) { logger.warning("Can't change to map module " + fNewModule); sPreventRegistration = false; return; } c = fNewModule.getModeController(); } if (!toBeSelected.isRoot()) { c.setFolded(toBeSelected.getParentNode(), false); } NodeView nodeView = c.getNodeView(toBeSelected); if (nodeView != null) { c.select(nodeView); sPreventRegistration = false; } } }); } private void printVector() { StringBuffer sb = new StringBuffer("\n"); int i = 0; for (Iterator iter = sNodeVector.iterator(); iter.hasNext();) { NodeHolder holder = (NodeHolder) iter.next(); sb.append(((sCurrentPosition - 1 == i) ? "==>" : " ") + "Node pos " + i + " is " + holder.getNode(getMindMapController().getController())); sb.append("\n"); i++; } logger.info(sb.toString() + "\n"); } }