/*FreeMind - A Program for creating and viewing Mindmaps *Copyright (C) 2000-2004 Joerg Mueller, Daniel Polansky, Christian Foltin 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 11.11.2010 */ package accessories.plugins; import java.util.Iterator; import java.util.Vector; import java.util.logging.Logger; import javax.swing.Action; import javax.swing.JMenuItem; import freemind.controller.MenuItemEnabledListener; import freemind.controller.actions.generated.instance.CompoundAction; import freemind.controller.actions.generated.instance.FoldAction; import freemind.controller.actions.generated.instance.HookNodeAction; import freemind.controller.actions.generated.instance.NewNodeAction; import freemind.controller.actions.generated.instance.NodeAction; import freemind.controller.actions.generated.instance.XmlAction; import freemind.extensions.HookRegistration; import freemind.main.Tools; import freemind.modes.MindMap; import freemind.modes.MindMapNode; import freemind.modes.ModeController; import freemind.modes.mindmapmode.MindMapController; import freemind.modes.mindmapmode.actions.NodeHookAction; import freemind.modes.mindmapmode.actions.xml.ActionHandler; import freemind.modes.mindmapmode.hooks.MindMapNodeHookAdapter; /** * This plugin stores the location of last edit taken place in order to jump to * it on keystroke. * * @author foltin */ public class JumpLastEditLocation extends MindMapNodeHookAdapter { public JumpLastEditLocation() { } public void invoke(MindMapNode pNode) { super.invoke(pNode); try { JumpLastEditLocationRegistration base = (JumpLastEditLocationRegistration) getPluginBaseClass(); MindMapNode node = base.getLastEditLocation(pNode); if (node == null) { return; } this.logger.fine("Selecting " + node + " as last edit location."); getMindMapController().select(node, Tools.getVectorWithSingleElement(node)); } catch (Exception e) { freemind.main.Resources.getInstance().logException(e); } } public static class JumpLastEditLocationRegistration implements HookRegistration, ActionHandler, MenuItemEnabledListener { private static final String PLUGIN_NAME = "accessories/plugins/JumpLastEditLocation.properties"; private MindMapController controller; private MindMap mMap; private Logger logger; private Vector mLastEditLocations = new Vector(); public MindMapNode getLastEditLocation(MindMapNode pCurrentNode) { int size = mLastEditLocations.size(); if (size == 0) { return null; } // search for the current node inside the vector: String id = controller.getNodeID(pCurrentNode); int index = mLastEditLocations.lastIndexOf(id); do { if(index < 0) { // current node not present, we start with the last position: index = size -1; } else { index = index - 1; if (index < 0) { index = 0; } } id = (String) mLastEditLocations.elementAt(index); try { pCurrentNode = controller.getNodeFromID(id); return pCurrentNode; } catch (Exception e) { freemind.main.Resources.getInstance().logException(e); } } while(index > 0); return null; } public JumpLastEditLocationRegistration(ModeController controller, MindMap map) { this.controller = (MindMapController) controller; mMap = map; logger = controller.getFrame().getLogger(this.getClass().getName()); } public void register() { controller.getActionFactory().registerHandler(this); } public void deRegister() { controller.getActionFactory().deregisterHandler(this); } public void executeAction(XmlAction action) { // detect format changes: detectFormatChanges(action); } /** */ private void detectFormatChanges(XmlAction doAction) { if (doAction instanceof CompoundAction) { CompoundAction compAction = (CompoundAction) doAction; for (Iterator i = compAction.getListChoiceList().iterator(); i .hasNext();) { XmlAction childAction = (XmlAction) i.next(); detectFormatChanges(childAction); } } else if ((doAction instanceof NodeAction) && !(doAction instanceof FoldAction)) { // remove myself: if (doAction instanceof HookNodeAction) { HookNodeAction hookAction = (HookNodeAction) doAction; if (Tools.safeEquals(hookAction.getHookName(), PLUGIN_NAME)) { return; } } String lastLocation = ((NodeAction) doAction).getNode(); if (doAction instanceof NewNodeAction) { NewNodeAction newNodeAction = (NewNodeAction) doAction; lastLocation = newNodeAction.getNewId(); } // prevent double entries if (mLastEditLocations.size() > 0 && Tools.safeEquals(lastLocation, mLastEditLocations.lastElement())) { return; } mLastEditLocations.add(lastLocation); if (mLastEditLocations.size() > 10) { mLastEditLocations.remove(0); } try { logger.fine("New last edit location: " + lastLocation + " from " + controller.marshall(doAction)); } catch (Exception e) { freemind.main.Resources.getInstance().logException(e); logger.warning("Not able to marshall the action " + doAction.getClass() + " as " + doAction); } } } public void startTransaction(String name) { } public void endTransaction(String name) { } public boolean isEnabled(JMenuItem pItem, Action pAction) { String hookName = ((NodeHookAction) pAction).getHookName(); if (PLUGIN_NAME.equals(hookName)) { // back is only enabled if there are already some nodes to go // back ;-) return !mLastEditLocations.isEmpty(); } return true; } } }