/*FreeMind - A Program for creating and viewing Mindmaps
*Copyright (C) 2000-2001 Joerg Mueller <joergmueller@bigfoot.com>
*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.
*/
package freemind.modes.browsemode;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.ListIterator;
import java.util.Vector;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JToolBar;
import freemind.controller.MenuBar;
import freemind.controller.MenuItemEnabledListener;
import freemind.controller.StructuredMenuHolder;
import freemind.extensions.HookFactory;
import freemind.main.Tools;
import freemind.main.XMLElement;
import freemind.main.XMLParseException;
import freemind.modes.MapAdapter;
import freemind.modes.MindMap;
import freemind.modes.MindMapNode;
import freemind.modes.Mode;
import freemind.modes.ModeController;
import freemind.modes.NodeAdapter;
import freemind.modes.common.GotoLinkNodeAction;
import freemind.modes.common.plugins.MapNodePositionHolderBase;
import freemind.modes.common.plugins.NodeNoteBase;
import freemind.modes.viewmodes.ViewControllerAdapter;
import freemind.view.mindmapview.MainView;
public class BrowseController extends ViewControllerAdapter {
private JPopupMenu popupmenu;
private JToolBar toolbar;
Action followLink;
Action nodeUp;
Action nodeDown;
private HookFactory mBrowseHookFactory;
private ImageIcon noteIcon;
public FollowMapLink followMapLink;
public static class FollowMapLink extends AbstractAction implements MenuItemEnabledListener {
private ViewControllerAdapter modeController;
private Logger logger;
public FollowMapLink(ViewControllerAdapter controller) {
super(controller.getText("follow_map_link"), MapNodePositionHolderBase.getMapLocationIcon());
this.modeController = controller;
logger = modeController.getFrame().getLogger(
this.getClass().getName());
}
public void actionPerformed(ActionEvent e) {
MapNodePositionHolderBase hook = getHook();
if (hook != null) {
String[] barePositions = hook.getBarePosition();
try {
// GRR, this is doubled code :-(
HashMap tileSources = new HashMap();
tileSources.put(
MapNodePositionHolderBase.TILE_SOURCE_MAPNIK,
MapNodePositionHolderBase.SHORT_MAPNIK);
tileSources.put(
MapNodePositionHolderBase.TILE_SOURCE_CYCLE_MAP,
MapNodePositionHolderBase.SHORT_CYCLE_MAP);
tileSources
.put(MapNodePositionHolderBase.TILE_SOURCE_TRANSPORT_MAP,
MapNodePositionHolderBase.SHORT_TRANSPORT_MAP);
tileSources
.put(MapNodePositionHolderBase.TILE_SOURCE_MAP_QUEST_OPEN_MAP,
MapNodePositionHolderBase.SHORT_MAP_QUEST_OPEN_MAP);
String link = "http://www.openstreetmap.org/?" + "mlat="
+ barePositions[0] + "&mlon=" + barePositions[1]
+ "&lat=" + barePositions[2] + "&lon="
+ barePositions[3] + "&zoom=" + barePositions[4]
+ "&layers=" + tileSources.get(barePositions[5]);
logger.fine("Try to open link " + link);
modeController.getFrame().openDocument(new URL(link));
} catch (MalformedURLException e1) {
freemind.main.Resources.getInstance().logException(e1);
} catch (Exception e1) {
freemind.main.Resources.getInstance().logException(e1);
}
}
}
protected MapNodePositionHolderBase getHook() {
MindMapNode selected = modeController.getSelected();
MapNodePositionHolderBase hook = MapNodePositionHolderBase
.getBaseHook(selected);
return hook;
}
/* (non-Javadoc)
* @see freemind.controller.MenuItemEnabledListener#isEnabled(javax.swing.JMenuItem, javax.swing.Action)
*/
public boolean isEnabled(JMenuItem pItem, Action pAction) {
return getHook() != null;
}
}
public BrowseController(Mode mode) {
super(mode);
mBrowseHookFactory = new BrowseHookFactory();
// Daniel: Actions are initialized here and not above because of
// some error it would produce. Not studied in more detail.
followLink = new FollowLinkAction();
followMapLink = new FollowMapLink(this);
popupmenu = new BrowsePopupMenu(this);
toolbar = new BrowseToolBar(this);
setAllActions(false);
// for displaying notes.
registerNodeSelectionListener(new NodeNoteViewer(this), false);
}
public void startupController() {
super.startupController();
invokeHooksRecursively((NodeAdapter) getRootNode(), getMap());
}
protected void restoreMapsLastState(ModeController pNewModeController,
MapAdapter pModel) {
// intentionally do nothing.
}
public MapAdapter newModel(ModeController modeController) {
return new BrowseMapModel(getFrame(), modeController);
}
public void plainClick(MouseEvent e) {
/* perform action only if one selected node. */
if (getSelecteds().size() != 1)
return;
final MainView component = (MainView) e.getComponent();
if (component.isInFollowLinkRegion(e.getX())) {
loadURL();
} else {
MindMapNode node = (component).getNodeView().getModel();
if (!node.hasChildren()) {
// the emulate the plain click.
doubleClick(e);
return;
}
toggleFolded.toggleFolded(getSelecteds().listIterator());
}
}
public void doubleClick() {
/* If the link exists, follow the link; toggle folded otherwise */
if (getSelected().getLink() == null) {
toggleFolded.toggleFolded();
} else {
loadURL();
}
}
// public void anotherNodeSelected(MindMapNode n) {
// super.anotherNodeSelected(n);
// if(n.isRoot()){
// return;
// }
// //Presentation:
// setFolded(n, false);
// foldOthers(n);
// }
//
//
// private void foldOthers(MindMapNode n) {
// if(n.isRoot()){
// return;
// }
// MindMapNode parent = n.getParentNode();
// for (Iterator iter = parent.childrenUnfolded(); iter.hasNext();) {
// MindMapNode element = (MindMapNode) iter.next();
// if(element != n){
// setFolded(element, true);
// }
// }
// foldOthers(parent);
// }
public MindMapNode newNode(Object userObject, MindMap map) {
return new BrowseNodeModel(userObject, getFrame(), map);
}
public JPopupMenu getPopupMenu() {
return popupmenu;
}
/**
* Link implementation: If this is a link, we want to make a popup with at
* least removelink available.
*/
public JPopupMenu getPopupForModel(java.lang.Object obj) {
if (obj instanceof BrowseArrowLinkModel) {
// yes, this is a link.
BrowseArrowLinkModel link = (BrowseArrowLinkModel) obj;
JPopupMenu arrowLinkPopup = new JPopupMenu();
arrowLinkPopup.add(getGotoLinkNodeAction(link.getSource()));
arrowLinkPopup.add(getGotoLinkNodeAction(link.getTarget()));
arrowLinkPopup.addSeparator();
// add all links from target and from source:
HashSet nodeAlreadyVisited = new HashSet();
nodeAlreadyVisited.add(link.getSource());
nodeAlreadyVisited.add(link.getTarget());
Vector links = getModel().getLinkRegistry().getAllLinks(
link.getSource());
links.addAll(getModel().getLinkRegistry().getAllLinks(
link.getTarget()));
for (int i = 0; i < links.size(); ++i) {
BrowseArrowLinkModel foreign_link = (BrowseArrowLinkModel) links
.get(i);
if (nodeAlreadyVisited.add(foreign_link.getTarget())) {
arrowLinkPopup.add(getGotoLinkNodeAction(foreign_link
.getTarget()));
}
if (nodeAlreadyVisited.add(foreign_link.getSource())) {
arrowLinkPopup.add(getGotoLinkNodeAction(foreign_link
.getSource()));
}
}
return arrowLinkPopup;
}
return null;
}
/**
*/
private GotoLinkNodeAction getGotoLinkNodeAction(MindMapNode destination) {
return new GotoLinkNodeAction(this, destination);
}
public JToolBar getModeToolBar() {
return getToolBar();
}
BrowseToolBar getToolBar() {
return (BrowseToolBar) toolbar;
}
// public void loadURL(String relative) {
// // copy from mind map controller:
// if (relative.startsWith("#")) {
// // inner map link, fc, 12.10.2004
// String target = relative.substring(1);
// try {
// MindMapNode node = getNodeFromID(target);
// centerNode(node);
// return;
// } catch (Exception e) {
// // bad luck.
// getFrame().out(Tools.expandPlaceholders(getText("link_not_found"),
// target));
// return;
// }
// }
//
// URL absolute = null;
// try {
// absolute = new URL(getMap().getURL(), relative);
// getFrame().out(absolute.toString());
// } catch (MalformedURLException ex) {
// freemind.main.Resources.getInstance().logExecption(ex);
// getController().errorMessage(
// getText("url_error") + " " + ex.getMessage());
// // getFrame().err(getText("url_error"));
// return;
// }
//
// String type = Tools.getExtension(absolute.getFile());
// try {
// if
// (type.equals(freemind.main.FreeMindCommon.FREEMIND_FILE_EXTENSION_WITHOUT_DOT))
// {
// getFrame().setWaitingCursor(true);
// load(absolute);
// } else {
// getFrame().openDocument(absolute);
// }
// } catch (Exception ex) {
// getController().errorMessage(getText("url_load_error") + absolute);
// freemind.main.Resources.getInstance().logExecption( ex);
// // for some reason, this exception is thrown anytime...
// } finally {
// getFrame().setWaitingCursor(false);
// }
//
// }
public ModeController load(URL url) throws IOException, XMLParseException,
URISyntaxException {
ModeController newModeController = super.load(url);
// decorator pattern.
((BrowseToolBar) newModeController.getModeToolBar()).setURLField(url
.toString());
return newModeController;
}
public ModeController load(File url) throws IOException {
ModeController newModeController = super.load(url);
// decorator pattern.
((BrowseToolBar) newModeController.getModeToolBar()).setURLField(Tools
.fileToUrl(url).toString());
return newModeController;
}
public void newMap(MindMap mapModel) {
setNoteIcon(mapModel.getRootNode());
super.newMap(mapModel);
}
private void setNoteIcon(MindMapNode node) {
String noteText = node.getNoteText();
if (noteText != null && !noteText.equals("")) {
// icon
if (noteIcon == null) {
noteIcon = new ImageIcon(getController().getResource(
"images/knotes.png"));
}
node.setStateIcon(NodeNoteBase.NODE_NOTE_ICON, noteIcon);
}
ListIterator children = node.childrenUnfolded();
while (children.hasNext()) {
setNoteIcon((MindMapNode) children.next());
}
}
/**
* Enabled/Disabled all actions that are dependent on whether there is a map
* open or not.
*/
protected void setAllActions(boolean enabled) {
super.setAllActions(enabled);
toggleFolded.setEnabled(enabled);
toggleChildrenFolded.setEnabled(enabled);
followLink.setEnabled(enabled);
}
// ////////
// Actions
// ///////
private class FollowLinkAction extends AbstractAction {
FollowLinkAction() {
super(getText("follow_link"));
}
public void actionPerformed(ActionEvent e) {
loadURL();
}
}
/*
* (non-Javadoc)
*
* @see freemind.modes.ModeController#updateMenus(freemind.controller.
* StructuredMenuHolder)
*/
public void updateMenus(StructuredMenuHolder holder) {
add(holder, MenuBar.EDIT_MENU + "/find/find", find, "keystroke_find");
add(holder, MenuBar.EDIT_MENU + "/find/findNext", findNext,
"keystroke_find_next");
add(holder, MenuBar.EDIT_MENU + "/find/followLink", followLink,
"keystroke_follow_link");
holder.addSeparator(MenuBar.EDIT_MENU + "/find");
add(holder, MenuBar.EDIT_MENU + "/find/toggleFolded", toggleFolded,
"keystroke_toggle_folded");
add(holder, MenuBar.EDIT_MENU + "/find/toggleChildrenFolded",
toggleChildrenFolded, "keystroke_toggle_children_folded");
}
public HookFactory getHookFactory() {
return mBrowseHookFactory;
}
public XMLElement createXMLElement() {
return new BrowseXMLElement(this);
}
}