/*FreeMind - A Program for creating and viewing Mindmaps *Copyright (C) 2000-2011 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. */ package plugins.map; //License: GPL. Copyright 2008 by Jan Peter Stotz import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.EventQueue; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.text.MessageFormat; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Vector; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.Timer; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import org.openstreetmap.gui.jmapviewer.Coordinate; import org.openstreetmap.gui.jmapviewer.JMapController; import org.openstreetmap.gui.jmapviewer.JMapViewer; import org.openstreetmap.gui.jmapviewer.OsmMercator; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; import org.openstreetmap.gui.jmapviewer.tilesources.AbstractOsmTileSource; import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource; import freemind.common.FreeMindTask; import freemind.common.XmlBindingTools; import freemind.controller.MenuItemEnabledListener; import freemind.controller.MenuItemSelectedListener; import freemind.controller.StructuredMenuHolder; import freemind.controller.actions.generated.instance.Place; import freemind.controller.actions.generated.instance.Result; import freemind.controller.actions.generated.instance.Reversegeocode; import freemind.controller.actions.generated.instance.Searchresults; import freemind.extensions.ExportHook; import freemind.main.Resources; import freemind.main.Tools; import freemind.modes.MindMapNode; import freemind.modes.ModeController; import freemind.modes.common.plugins.MapNodePositionHolderBase; import freemind.modes.mindmapmode.MindMapController; import freemind.view.mindmapview.EditNodeBase; import freemind.view.mindmapview.EditNodeTextField; import freemind.view.mindmapview.NodeView; /** * Default map controller which implements map moving by pressing the right * mouse button and zooming by double click or by mouse wheel. * * @author Jan Peter Stotz * * FreeMind Extensions: - Move with button 1 (consistency with FreeMind * UI) OK - Single click for Set Cursor OK - Mouse Wheel: Zoom OK - * Control-Mouse Wheel: ? - (Right click +) Menu: popup menu mit * If * right click, then the cursor is set to that position (consistency * with FM-UI) * Place node(s) ==> the node gets a * {@link MapMarkerLocation} here. The position, the position of the map * and the zoom is stored in the node. * * * Node Extra Menu Items: * Show node(s) in Map ==> Chooses the best * view for the nodes and selects them. * * * FIXME: On undo place node, the position is gone. (Undo action * contains the initial zeros, I guess). */ public class FreeMindMapController extends JMapController implements MouseListener, MouseMotionListener, MouseWheelListener, ActionListener, KeyListener { /** * @author foltin * @date 27.07.2012 */ public interface CursorPositionListener { void cursorPositionChanged(Coordinate pCursorPosition); } /** * */ private static final int MODIFIERS_WITHOUT_SHIFT = Integer.MAX_VALUE ^ KeyEvent.SHIFT_MASK; private static final String NODE_MAP_HOME_PROPERTY = "node_map_home"; private static final String MAP_DIALOG_PROGRESS_MESSAGE = "MapDialog.progressMessage"; private static final String MAP_DIALOG_ADD_PLACES = "MapDialog.addPlaces"; private static final String XML_VERSION_1_0_ENCODING_UTF_8 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; private static final int MOUSE_BUTTONS_MASK = MouseEvent.BUTTON3_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK; private static final int MAC_MOUSE_BUTTON3_MASK = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK; private static final int MAC_MOUSE_BUTTON1_MASK = MouseEvent.BUTTON1_DOWN_MASK; private static final int SCROLL_MARGIN = 5; private static final int SCROLL_PIXEL_AMOUNT = 25; private static final String OSM_NOMINATIM_CONNECT_TIMEOUT_IN_MS = "osm_nominatim_connect_timeout_in_ms"; private static final String OSM_NOMINATIM_READ_TIMEOUT_IN_MS = "osm_nominatim_read_timeout_in_ms"; private static final int MOVE_PIXEL_AMOUNT = 50; private static final float PAGE_DOWN_FACTOR = 0.85f; private static final int POSITION_HOLDER_LIMIT = 50; private static final long WHEEL_ZOOM_MINIMAL_TIME_BETWEEN_CHANGES = 333; protected static java.util.logging.Logger logger = freemind.main.Resources .getInstance().getLogger("plugins.map.FreeMindMapController"); private JPopupMenu mPopupMenu = new JPopupMenu(); private final MindMapController mMindMapController; private final JDialog mMapDialog; private final MapDialog mMapHook; private Point lastDragPoint; private Point mDragStartingPoint; private boolean mMovementEnabled = true; private boolean isMoving = false; private boolean mClickEnabled = true; private int movementMouseButton = MouseEvent.BUTTON1; private int movementMouseButtonMask = MouseEvent.BUTTON1_DOWN_MASK; private boolean mWheelZoomEnabled = true; private JPopupMenu mContextPopupMenu; private MapNodePositionHolder mCurrentPopupPositionHolder; private boolean isMapNodeMoving = false; private MapNodePositionHolder mMapNodeMovingSource = null; private Timer mMouseHitsNodeTimer; private boolean mIsRectangularSelect; private Coordinate mRectangularStart; private Vector mPositionHolderVector = new Vector(); /** * Marks the index of the current position or -1 if none. */ private int mPositionHolderIndex = -1; public static class TileSourceStore { TileSource mTileSource; String mLayerName; public TileSourceStore(TileSource pTileSource, String pLayerName) { super(); mTileSource = pTileSource; mLayerName = pLayerName; } } public static class TransportMap extends AbstractOsmTileSource { // http://b.tile2.opencyclemap.org/transport/14/8800/5373.png private static final String PATTERN = "http://%s.tile2.opencyclemap.org/transport"; private static final String[] SERVER = { "a", "b", "c" }; private int SERVER_NUM = 0; public TransportMap() { super("OSM Transport Map", PATTERN); } public String getBaseUrl() { String url = String.format(this.baseUrl, new Object[] { SERVER[SERVER_NUM] }); SERVER_NUM = (SERVER_NUM + 1) % SERVER.length; return url; } public int getMaxZoom() { return 18; } public TileUpdate getTileUpdate() { return TileUpdate.LastModified; } } public static class MapQuestOpenMap extends AbstractOsmTileSource { // http://otile1.mqcdn.com/tiles/1.0.0/osm/14/8800/5374.png private static final String PATTERN = "http://otile%s.mqcdn.com/tiles/1.0.0/osm"; private static final String[] SERVER = { "1", "2", "3", "4" }; private int SERVER_NUM = 0; public MapQuestOpenMap() { super("OSM MapQuest.Open Map", PATTERN); } public String getBaseUrl() { String url = String.format(this.baseUrl, new Object[] { SERVER[SERVER_NUM] }); SERVER_NUM = (SERVER_NUM + 1) % SERVER.length; return url; } public int getMaxZoom() { return 18; } public TileUpdate getTileUpdate() { return TileUpdate.LastModified; } } private static TileSourceStore[] sTileSources = new TileSourceStore[] { new TileSourceStore(new OsmTileSource.Mapnik(), MapNodePositionHolderBase.SHORT_MAPNIK), new TileSourceStore(new OsmTileSource.CycleMap(), MapNodePositionHolderBase.SHORT_CYCLE_MAP), new TileSourceStore(new TransportMap(), MapNodePositionHolderBase.SHORT_TRANSPORT_MAP), new TileSourceStore(new MapQuestOpenMap(), MapNodePositionHolderBase.SHORT_MAP_QUEST_OPEN_MAP) /* , new BingAerialTileSource() license problems.... */ }; private final class MapEditTextFieldControl implements EditNodeBase.EditControl { private final NodeView mNodeView; private final MindMapNode mNewNode; private final MindMapNode mTargetNode; private boolean mIsEditOfExistingNode; private MapEditTextFieldControl(NodeView pNodeView, MindMapNode pNewNode, MindMapNode pTargetNode, boolean pIsEditOfExistingNode) { mNodeView = pNodeView; mNewNode = pNewNode; mTargetNode = pTargetNode; mIsEditOfExistingNode = pIsEditOfExistingNode; } public void cancel() { if (!mIsEditOfExistingNode) { mMindMapController.getView().selectAsTheOnlyOneSelected( mNodeView); mMindMapController.cut(Tools .getVectorWithSingleElement(mNewNode)); mMindMapController.select(mMindMapController .getNodeView(mTargetNode)); } endEdit(); } public void ok(String newText) { mMindMapController.setNodeText(mNewNode, newText); MapNodePositionHolderBase hook = placeNode(mNewNode); endEdit(); } private void endEdit() { setMouseControl(true); mMindMapController.setBlocked(false); mMapDialog.requestFocus(); } public void split(String newText, int position) { } } private final class MapEditNoteTextField extends EditNodeTextField { private final Point mPoint; private MapEditNoteTextField(NodeView pNode, String pText, KeyEvent pFirstEvent, ModeController pController, EditControl pEditControl, JComponent pParent, Point pPoint) { super(pNode, pText, pFirstEvent, pController, pEditControl, pParent, pParent); mPoint = pPoint; } protected void setTextfieldLoaction(Point pMPoint) { textfield.setLocation(mPoint); } protected void addTextfield() { // add to front to make it visible over the map. mParent.add(textfield); } } /** * @author foltin * @date 16.11.2011 */ public class ChangeTileSource extends AbstractAction implements MenuItemSelectedListener { private final TileSource mSource; /** * @param pSource */ public ChangeTileSource(TileSource pSource) { super(Resources.getInstance().getText( "map_ChangeTileSource_" + getTileSourceName(pSource))); mSource = pSource; } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent * ) */ public void actionPerformed(ActionEvent pE) { map.setTileSource(mSource); } /* * (non-Javadoc) * * @see * freemind.controller.MenuItemSelectedListener#isSelected(javax.swing * .JMenuItem, javax.swing.Action) */ public boolean isSelected(JMenuItem pCheckItem, Action pAction) { return getTileSource() == mSource; } } /** * @author foltin * @date 31.10.2011 */ private final class PlaceNodeAction extends AbstractAction { public PlaceNodeAction() { super(getText("MapControllerPopupDialog.place"), MapNodePositionHolder.getMapLocationIcon()); } public void actionPerformed(ActionEvent actionEvent) { placeNode(mMindMapController.getSelected()); } } /** * @author foltin * @date 31.10.2011 */ private final class ShowNodeAction extends AbstractAction { public ShowNodeAction() { super(getText("MapControllerPopupDialog.show_nodes")); } public void actionPerformed(ActionEvent actionEvent) { showSelectedNodes(); } } /** * @author foltin * @date 31.10.2011 */ private abstract class MoveAction extends AbstractAction { /** * @param pText */ public MoveAction(String pText) { super(pText); } public void actionPerformed(ActionEvent actionEvent) { if (!searchForNearestNode(false)) { searchForNearestNode(true); } } /** * @param alternative * @return true, if a node was found */ protected boolean searchForNearestNode(boolean alternative) { boolean returnValue = false; Coordinate cursorPosition = getMap().getCursorPosition(); // get map marker locations: HashSet mapNodePositionHolders = new HashSet( mMapHook.getMapNodePositionHolders()); logger.fine("Before removal " + mapNodePositionHolders.size() + " elements"); // take only those elements in the correct quadrant (eg. -45° - // +45°) which are not identical to the current for (Iterator it = mapNodePositionHolders.iterator(); it.hasNext();) { MapNodePositionHolder holder = (MapNodePositionHolder) it .next(); Coordinate pointPosition = holder.getPosition(); boolean inDestinationQuadrant = destinationQuadrantCheck( cursorPosition, pointPosition, alternative); if (!inDestinationQuadrant || safeEquals(pointPosition, cursorPosition)) { it.remove(); } } logger.fine("After removal " + mapNodePositionHolders.size() + " elements"); // now, we have all points on the left angle (eg. -45° to 45°) and // search // for the nearest MapNodePositionHolder nearest = null; double distance = Double.MAX_VALUE; for (Iterator it = mapNodePositionHolders.iterator(); it.hasNext();) { MapNodePositionHolder holder = (MapNodePositionHolder) it .next(); double newDist = dist(holder.getPosition(), cursorPosition); logger.fine("Position " + holder + " is " + newDist); if (newDist < distance) { distance = newDist; nearest = holder; } } if (nearest != null) { selectNode(nearest.getNode()); // don't change the zoom setCursorPosition(nearest, map.getZoom()); returnValue = true; } return returnValue; } public boolean destinationQuadrantCheck(Coordinate cursorPosition, Coordinate pointPosition, boolean alternative) { int mapZoomMax = getMaxZoom(); int x1 = OsmMercator.LonToX(cursorPosition.getLon(), mapZoomMax); int y1 = OsmMercator.LatToY(cursorPosition.getLat(), mapZoomMax); int x2 = OsmMercator.LonToX(pointPosition.getLon(), mapZoomMax); int y2 = OsmMercator.LatToY(pointPosition.getLat(), mapZoomMax); return destinationQuadrantCheck(x1, y1, x2, y2, alternative); } /** * If no point was found from the destinationQuadrantCheck, here, * alternative = true is tried */ public abstract boolean destinationQuadrantCheck(int x1, int y1, int x2, int y2, boolean alternative); /** * @param pPointPosition * @param pCursorPosition * @return */ private boolean safeEquals(Coordinate p1, Coordinate p2) { return (p1 != null && p2 != null && p1.getLon() == p2.getLon() && p1 .getLat() == p2.getLat()) || (p1 == null && p2 == null); } /** * @param pPosition * @param pCursorPosition * @return */ private double dist(Coordinate p1, Coordinate p2) { return OsmMercator.getDistance(p1.getLat(), p1.getLon(), p2.getLat(), p2.getLon()); } } private final class MoveLeftAction extends MoveAction { /** * */ public MoveLeftAction() { super(getText("MapControllerPopupDialog.moveLeft")); } public boolean destinationQuadrantCheck(int x1, int y1, int x2, int y2, boolean alternative) { if (alternative) return x2 < x1; return x2 < x1 && Math.abs(y2 - y1) < Math.abs(x2 - x1); } } private final class MoveRightAction extends MoveAction { /** * */ public MoveRightAction() { super(getText("MapControllerPopupDialog.moveRight")); } public boolean destinationQuadrantCheck(int x1, int y1, int x2, int y2, boolean alternative) { if (alternative) return x2 > x1; return x2 > x1 && Math.abs(y2 - y1) < Math.abs(x2 - x1); } } private final class MoveUpAction extends MoveAction { /** * */ public MoveUpAction() { super(getText("MapControllerPopupDialog.moveUp")); } public boolean destinationQuadrantCheck(int x1, int y1, int x2, int y2, boolean alternative) { if (alternative) return y2 < y1; return y2 < y1 && Math.abs(y2 - y1) > Math.abs(x2 - x1); } } private final class MoveDownAction extends MoveAction { /** * */ public MoveDownAction() { super(getText("MapControllerPopupDialog.moveDown")); } public boolean destinationQuadrantCheck(int x1, int y1, int x2, int y2, boolean alternative) { if (alternative) return y2 > y1; return y2 > y1 && Math.abs(y2 - y1) > Math.abs(x2 - x1); } } private final class MoveForwardAction extends AbstractAction implements MenuItemEnabledListener { public MoveForwardAction() { super(getText("MapControllerPopupDialog.moveForward")); } public void actionPerformed(ActionEvent pE) { if (isEnabledCheck()) { PositionHolder posHolder = (PositionHolder) getPositionHolderVector() .get(getPositionHolderIndex() + 1); getMap().setCursorPosition(posHolder.getCoordinate()); map.setDisplayPositionByLatLon(posHolder.lat, posHolder.lon, posHolder.zoom); setPositionHolderIndex(getPositionHolderIndex() + 1); } } protected boolean isEnabledCheck() { return getPositionHolderIndex() >= 0 && getPositionHolderIndex() < getPositionHolderVector() .size() - 1; } public boolean isEnabled(JMenuItem pItem, Action pAction) { return isEnabledCheck(); } } private final class MoveBackwardAction extends AbstractAction implements MenuItemEnabledListener { public MoveBackwardAction() { super(getText("MapControllerPopupDialog.moveBackward")); } public void actionPerformed(ActionEvent pE) { if (isEnabledCheck()) { PositionHolder posHolder = (PositionHolder) getPositionHolderVector() .get(getPositionHolderIndex() - 1); getMap().setCursorPosition(posHolder.getCoordinate()); map.setDisplayPositionByLatLon(posHolder.lat, posHolder.lon, posHolder.zoom); setPositionHolderIndex(getPositionHolderIndex() - 1); } } protected boolean isEnabledCheck() { return getPositionHolderIndex() > 0; } public boolean isEnabled(JMenuItem pItem, Action pAction) { return isEnabledCheck(); } } public final static class PositionHolder { double lat; double lon; int zoom; public PositionHolder(double pLat, double pLon, int pZoom) { super(); lat = pLat; lon = pLon; zoom = pZoom; } public String toString() { return "PositionHolder [lat=" + lat + ", lon=" + lon + ", zoom=" + zoom + "]"; } public Coordinate getCoordinate() { return new Coordinate(lat, lon); } public int hashCode() { final int prime = 31; int result = 1; long temp; temp = Double.doubleToLongBits(lat); result = prime * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(lon); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + zoom; return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PositionHolder other = (PositionHolder) obj; if (Double.doubleToLongBits(lat) != Double .doubleToLongBits(other.lat)) return false; if (Double.doubleToLongBits(lon) != Double .doubleToLongBits(other.lon)) return false; if (zoom != other.zoom) return false; return true; } } private final class MoveHomeAction extends AbstractAction implements MenuItemEnabledListener { public MoveHomeAction() { super(getText("MapControllerPopupDialog.MoveHome")); } public void actionPerformed(ActionEvent pE) { PositionHolder posHolder = getPosHolder(); if (posHolder == null) { return; } setZoom(posHolder.zoom); Coordinate coordinates = posHolder.getCoordinate(); setCursorPosition(coordinates); } public PositionHolder getPosHolder() { try { String homeProperty = Resources.getInstance().getProperty( NODE_MAP_HOME_PROPERTY); if (homeProperty == null || homeProperty.isEmpty()) { return null; } String[] splitResult = homeProperty.split(":"); if (splitResult.length != 3) { return null; } double lat = Double.parseDouble(splitResult[0]); double lon = Double.parseDouble(splitResult[1]); int zoom = Integer.parseInt(splitResult[2]); return new PositionHolder(lat, lon, zoom); } catch (Exception e) { freemind.main.Resources.getInstance().logException(e); return null; } } public boolean isEnabled(JMenuItem pItem, Action pAction) { return getPosHolder() != null; } } private final class SetHomeAction extends AbstractAction { /** * */ public SetHomeAction() { super(getText("MapControllerPopupDialog.SetHome")); } public void actionPerformed(ActionEvent pE) { Coordinate cursorPosition = getMap().getCursorPosition(); String propertyValue = cursorPosition.getLat() + ":" + cursorPosition.getLon() + ":" + map.getZoom(); mMindMapController.getController().setProperty( NODE_MAP_HOME_PROPERTY, propertyValue); } } private final class SetDisplayToFitMapMarkers extends AbstractAction { public SetDisplayToFitMapMarkers() { super(getText("MapControllerPopupDialog.SetDisplayToFitMapMarkers")); } public void actionPerformed(ActionEvent pE) { map.setDisplayToFitMapMarkers(); } } private final class ShowMapMarker extends AbstractAction implements MenuItemSelectedListener { public ShowMapMarker() { super(getText("MapControllerPopupDialog.ShowMapMarker")); } public void actionPerformed(ActionEvent pE) { map.setMapMarkerVisible(!map.getMapMarkersVisible()); } public boolean isSelected(JMenuItem pCheckItem, Action pAction) { return map.getMapMarkersVisible(); } } private final class TileGridVisible extends AbstractAction implements MenuItemSelectedListener { public TileGridVisible() { super(getText("MapControllerPopupDialog.TileGridVisible")); } public void actionPerformed(ActionEvent pE) { map.setTileGridVisible(!map.isTileGridVisible()); } public boolean isSelected(JMenuItem pCheckItem, Action pAction) { return map.isTileGridVisible(); } } private final class ZoomControlsVisible extends AbstractAction implements MenuItemSelectedListener { public ZoomControlsVisible() { super(getText("MapControllerPopupDialog.ZoomControlsVisible")); } public void actionPerformed(ActionEvent pE) { map.setZoomContolsVisible(!map.getZoomContolsVisible()); } public boolean isSelected(JMenuItem pCheckItem, Action pAction) { return map.getZoomContolsVisible(); } } private final class HideFoldedNodes extends AbstractAction implements MenuItemSelectedListener { public HideFoldedNodes() { super(getText("MapControllerPopupDialog.HideFoldedNodes")); } public void actionPerformed(ActionEvent pE) { getMap().setHideFoldedNodes(!getMap().isHideFoldedNodes()); mMapHook.addMarkersToMap(); } public boolean isSelected(JMenuItem pCheckItem, Action pAction) { return getMap().isHideFoldedNodes(); } } private final class SearchControlVisible extends AbstractAction implements MenuItemSelectedListener { public SearchControlVisible() { super(getText("MapControllerPopupDialog.SearchControlVisible")); } public void actionPerformed(ActionEvent pE) { mMapHook.toggleSearchBar(); } public boolean isSelected(JMenuItem pCheckItem, Action pAction) { return mMapHook.isSearchBarVisible(); } } private final class LimitSearchToRegionAction extends AbstractAction implements MenuItemSelectedListener { public LimitSearchToRegionAction() { super(getText("MapControllerPopupDialog.LimitSearchToRegionAction")); } public void actionPerformed(ActionEvent pE) { mMapHook.toggleLimitSearchToRegion(); mMapHook.focusSearchTerm(); } public boolean isSelected(JMenuItem pCheckItem, Action pAction) { return mMapHook.isLimitSearchToRegion(); } } private final class GotoSearch extends AbstractAction { public GotoSearch() { super(getText("MapControllerPopupDialog.GotoSearch")); } public void actionPerformed(ActionEvent pE) { if (!mMapHook.isSearchBarVisible()) { mMapHook.toggleSearchBar(); } else { mMapHook.focusSearchTerm(); } } } private final class AddMapPictureToNode extends AbstractAction { public AddMapPictureToNode() { super(getText("MapControllerPopupDialog.AddMapPictureToNode")); } public void actionPerformed(ActionEvent pE) { addMapPictureToNode(); } } private final class NewNodeAction extends AbstractAction { public NewNodeAction() { super(getText("MapControllerPopupDialog.NewNodeAction")); } public void actionPerformed(ActionEvent pE) { Point pos = getMap().getMapPosition(getMap().getCursorPosition(), true); MouseEvent e = new MouseEvent(map, 0, 0, 0, pos.x, pos.y, 1, false); newNode(e); } } private final class NewNodeReverseLookupAction extends AbstractAction { public NewNodeReverseLookupAction() { super( getText("MapControllerPopupDialog.NewNodeReverseLookupAction")); } public void actionPerformed(ActionEvent pE) { Coordinate pos = getMap().getCursorPosition(); Reversegeocode reverseLookup = getReverseLookup(pos, getMap() .getZoom()); if (reverseLookup != null) { for (Iterator it = reverseLookup.getListResultList().iterator(); it .hasNext();) { Result result = (Result) it.next(); addNode(mMindMapController.getSelected(), result.getContent(), result.getLat(), result.getLon()); } } } } private final class EditNodeInContextMenu extends AbstractAction { public EditNodeInContextMenu() { super(getText("MapControllerPopupDialog.EditNodeInContextMenu")); } public void actionPerformed(ActionEvent pE) { if (mCurrentPopupPositionHolder == null) { return; } setCursorPosition(mCurrentPopupPositionHolder.getPosition()); Point pos = getMap().getMapPosition( mCurrentPopupPositionHolder.getPosition(), true); // unfold node (and its parents): MindMapNode node = mCurrentPopupPositionHolder.getNode(); while (!node.isRoot()) { if (node.isFolded()) { mMindMapController.setFolded(node, false); } node = node.getParentNode(); } pos = MapMarkerLocation.adjustToTextfieldLocation(pos); MouseEvent e = new MouseEvent(map, 0, 0, 0, pos.x, pos.y, 1, false); editNode(mCurrentPopupPositionHolder, e); } } private final class MaxmimalZoomToCursorAction extends AbstractAction { private static final int CURSOR_MAXIMAL_ZOOM_HANDBREAK = 2; public MaxmimalZoomToCursorAction() { super( getText("MapControllerPopupDialog.MaxmimalZoomToCursorAction")); } public void actionPerformed(ActionEvent pE) { Coordinate cursorPosition = getMap().getCursorPosition(); int zoom = getMaxZoom() - CURSOR_MAXIMAL_ZOOM_HANDBREAK; if (getMap().getZoom() >= zoom) { zoom += CURSOR_MAXIMAL_ZOOM_HANDBREAK; } map.setDisplayPositionByLatLon(cursorPosition.getLat(), cursorPosition.getLon(), zoom); } } private final class ZoomAction extends AbstractAction { private final int mZoomDelta; public ZoomAction(int pZoomDelta) { super(getText("MapControllerPopupDialog.ZoomAction" + pZoomDelta)); mZoomDelta = pZoomDelta; } public void actionPerformed(ActionEvent pE) { Coordinate mapCenter = getMap().getPosition(); int zoom = getMap().getZoom() + mZoomDelta; if (zoom < JMapViewer.MIN_ZOOM) { zoom = JMapViewer.MIN_ZOOM; } if (zoom > getMaxZoom()) { zoom = getMaxZoom(); } map.setDisplayPositionByLatLon(mapCenter.getLat(), mapCenter.getLon(), zoom); } } private final class CopyLinkToClipboardAction extends AbstractAction { public CopyLinkToClipboardAction() { super(getText("MapControllerPopupDialog.CopyLinkToClipboardAction")); } public void actionPerformed(ActionEvent pE) { String link; if (mCurrentPopupPositionHolder != null) { link = getLink(mCurrentPopupPositionHolder); } else { Coordinate cursorPosition = getMap().getCursorPosition(); Coordinate position = getMap().getPosition(); int zoom = getMap().getZoom(); link = getLink(getTileSourceAsString(), cursorPosition, position, zoom); } // Put link into clipboard. Tools.getClipboard().setContents(new StringSelection(link), null); } } private final class CopyCoordinatesToClipboardAction extends AbstractAction { public CopyCoordinatesToClipboardAction() { super( getText("MapControllerPopupDialog.CopyCoordinatesToClipboardAction")); } public void actionPerformed(ActionEvent pE) { String coordinates; if (mCurrentPopupPositionHolder != null) { coordinates = getCoordinates(mCurrentPopupPositionHolder .getPosition()); } else { coordinates = getCoordinates(getMap().getCursorPosition()); } // Put Coordinates into clipboard. Tools.getClipboard().setContents(new StringSelection(coordinates), null); } /** * @param pCoordinate * @return */ private String getCoordinates(Coordinate pCoordinate) { return pCoordinate.getLat() + " " + pCoordinate.getLon(); } } private final class ShowNodeMapInContextMenu extends AbstractAction { public ShowNodeMapInContextMenu() { super(getText("MapControllerPopupDialog.ShowNodeMapInContextMenu")); } public void actionPerformed(ActionEvent pE) { if (mCurrentPopupPositionHolder != null) { showNode(mCurrentPopupPositionHolder); } } } private final class SelectNodeInContextMenu extends AbstractAction { public SelectNodeInContextMenu() { super(getText("MapControllerPopupDialog.SelectNodeInContextMenu")); } public void actionPerformed(ActionEvent pE) { if (mCurrentPopupPositionHolder != null) { selectContextMenuNode(); } } } private final class SelectNodeAndCloseInContextMenu extends AbstractAction { public SelectNodeAndCloseInContextMenu() { super( getText("MapControllerPopupDialog.SelectNodeAndCloseInContextMenu")); } public void actionPerformed(ActionEvent pE) { if (mCurrentPopupPositionHolder != null) { selectContextMenuNode(); mMapHook.disposeDialog(); } } } private final class RemoveNodeLocationInContextMenu extends AbstractAction { public RemoveNodeLocationInContextMenu() { super( getText("MapControllerPopupDialog.RemoveNodeLocationInContextMenu")); } public void actionPerformed(ActionEvent pE) { if (mCurrentPopupPositionHolder != null) { MindMapNode node = mCurrentPopupPositionHolder.getNode(); removeNodePosition(node); } } } private final class ExportMapAction extends AbstractAction { public ExportMapAction() { super(getText("MapControllerPopupDialog.ExportMapMenu")); } public void actionPerformed(ActionEvent pE) { File chosenFile = ExportHook.chooseImageFile("png", getText("Portable_Network_Graphic"), null, mMindMapController); if (chosenFile == null) { return; } boolean zoomContolsVisible = map.getZoomContolsVisible(); try { mMindMapController.getFrame().setWaitingCursor(true); map.setZoomContolsVisible(false); // Create an image containing the map: BufferedImage myImage = (BufferedImage) map.createImage( map.getWidth(), map.getHeight()); map.print(myImage.getGraphics()); FileOutputStream out = new FileOutputStream(chosenFile); ImageIO.write(myImage, "png", out); out.close(); } catch (IOException e1) { freemind.main.Resources.getInstance().logException(e1); } map.setZoomContolsVisible(zoomContolsVisible); mMindMapController.getFrame().setWaitingCursor(false); return; } } JCursorMapViewer getMap() { return (JCursorMapViewer) map; } /** * */ public void addMapPictureToNode() { if (mCurrentPopupPositionHolder == null) { // strange. return; } addPictureToNode(mCurrentPopupPositionHolder, mMindMapController); } public static void addPictureToNode(MapNodePositionHolder positionHolder, MindMapController mindMapController) { // create picture if not present: File tooltipFile = positionHolder.getTooltipFile(true); if (!tooltipFile.exists()) { if (!positionHolder.createToolTip(true)) { // an error occurred, sorry. return; } } MindMapNode selected = positionHolder.getNode(); MindMapNode addNewNode = mindMapController.addNewNode(selected, 0, selected.isLeft()); mindMapController .setNodeText(addNewNode, positionHolder.getImageHtml()); } public FreeMindMapController(JMapViewer map, MindMapController pMindMapController, final JDialog pMapDialog, MapDialog pMapHook) { super(map); mMapHook = pMapHook; mMindMapController = pMindMapController; mMapDialog = pMapDialog; mMouseHitsNodeTimer = new Timer(500, this); mMouseHitsNodeTimer.setRepeats(false); Action placeAction = new PlaceNodeAction(); Action showAction = new ShowNodeAction(); mZoomInAction = new ZoomAction(1); mZoomOutAction = new ZoomAction(-1); Action setDisplayToFitMapMarkers = new SetDisplayToFitMapMarkers(); Action showMapMarker = new ShowMapMarker(); Action tileGridVisible = new TileGridVisible(); Action zoomControlsVisible = new ZoomControlsVisible(); Action searchControlVisible = new SearchControlVisible(); Action gotoSearch = new GotoSearch(); Action hideFoldedNodes = new HideFoldedNodes(); Action newNodeAction = new NewNodeAction(); // Action newNodeReverseLookupAction = new NewNodeReverseLookupAction(); Action maxmimalZoomToCursorAction = new MaxmimalZoomToCursorAction(); Action copyLinkToClipboardAction = new CopyLinkToClipboardAction(); Action copyCoordinatesToClipboardAction = new CopyCoordinatesToClipboardAction(); Action exportAction = new ExportMapAction(); /** Menu **/ StructuredMenuHolder menuHolder = new StructuredMenuHolder(); mMenuBar = new JMenuBar(); JMenu mainItem = new JMenu(getText("MapControllerPopupDialog.Actions")); menuHolder.addMenu(mainItem, "main/actions/."); addAccelerator(menuHolder.addAction(placeAction, "main/actions/place"), "keystroke_plugins/map/MapDialog_Place"); menuHolder.addAction(exportAction, "main/actions/exportPng"); addAccelerator(menuHolder.addAction(pMapHook.getCloseAction(), "main/actions/close"), "keystroke_plugins/map/MapDialog_Close"); JMenu searchItem = new JMenu(getText("MapControllerPopupDialog.Search")); menuHolder.addMenu(searchItem, "main/search/."); addAccelerator(menuHolder.addAction(searchControlVisible, "main/search/showSearchControl"), "keystroke_plugins/map/MapDialog_toggle_search"); addAccelerator( menuHolder.addAction(gotoSearch, "main/search/gotoSearch"), "keystroke_plugins/map/MapDialog_goto_search"); addAccelerator(menuHolder.addAction(new LimitSearchToRegionAction(), "main/search/limitSearchToRegion"), "keystroke_plugins/map/MapDialog_limitSearchToRegion"); JMenu viewItem = new JMenu(getText("MapControllerPopupDialog.Views")); menuHolder.addMenu(viewItem, "main/view/."); menuHolder.addAction(showAction, "main/view/showNode"); menuHolder.addAction(setDisplayToFitMapMarkers, "main/view/setDisplayToFitMapMarkers"); menuHolder.addSeparator("main/view/"); for (int i = 0; i < sTileSources.length; i++) { TileSource source = sTileSources[i].mTileSource; addAccelerator(menuHolder.addAction(new ChangeTileSource(source), "main/view/" + i), "keystroke_plugins/map/MapDialog_tileSource_" + i); } menuHolder.addSeparator("main/view/"); menuHolder.addAction(showMapMarker, "main/view/showMapMarker"); menuHolder.addAction(tileGridVisible, "main/view/tileGridVisible"); menuHolder.addAction(zoomControlsVisible, "main/view/zoomControlsVisible"); addAccelerator(menuHolder.addAction(hideFoldedNodes, "main/view/hideFoldedNodes"), "keystroke_plugins/map/MapDialog_hideFoldedNodes"); menuHolder.addSeparator("main/view/"); addAccelerator( menuHolder.addAction(mZoomInAction, "main/view/ZoomInAction"), "keystroke_plugins/map/MapDialog_zoomIn"); addAccelerator( menuHolder.addAction(mZoomOutAction, "main/view/ZoomOutAction"), "keystroke_plugins/map/MapDialog_zoomOut"); JMenu navigationItem = new JMenu( getText("MapControllerPopupDialog.Navigation")); menuHolder.addMenu(navigationItem, "main/navigation/."); // menuHolder.addSeparator("main/navigation/"); addAccelerator(menuHolder.addAction(new SetHomeAction(), "main/navigation/SetHome"), "keystroke_plugins/map/MapDialogSetHome"); addAccelerator(menuHolder.addAction(new MoveHomeAction(), "main/navigation/MoveHome"), "keystroke_plugins/map/MapDialogMoveHome"); menuHolder.addSeparator("main/navigation/"); mMoveBackwardAction = new MoveBackwardAction(); addAccelerator(menuHolder.addAction(mMoveBackwardAction, "main/navigation/moveBackward"), "keystroke_plugins/map/MapDialog_moveBackward"); mMoveForwardAction = new MoveForwardAction(); addAccelerator(menuHolder.addAction(mMoveForwardAction, "main/navigation/moveForward"), "keystroke_plugins/map/MapDialog_moveForward"); menuHolder.addSeparator("main/navigation/"); addAccelerator(menuHolder.addAction(new MoveLeftAction(), "main/navigation/moveLeft"), "keystroke_plugins/map/MapDialog_moveLeft"); addAccelerator(menuHolder.addAction(new MoveRightAction(), "main/navigation/moveRight"), "keystroke_plugins/map/MapDialog_moveRight"); addAccelerator(menuHolder.addAction(new MoveUpAction(), "main/navigation/moveUp"), "keystroke_plugins/map/MapDialog_moveUp"); addAccelerator(menuHolder.addAction(new MoveDownAction(), "main/navigation/moveDown"), "keystroke_plugins/map/MapDialog_moveDown"); menuHolder.addSeparator("main/navigation/"); menuHolder.updateMenus(mMenuBar, "main/"); mMapDialog.setJMenuBar(mMenuBar); /* Popup menu */ menuHolder.addAction(newNodeAction, "popup/newNode"); // currently disabled, as the reverse functionality from // nominatim doesn't convince me. // menuHolder.addAction(newNodeReverseLookupAction, // "popup/newNodeReverseLookup"); menuHolder.addAction(placeAction, "popup/place"); menuHolder.addSeparator("popup/"); menuHolder.addAction(maxmimalZoomToCursorAction, "popup/maxmimalZoomToCursorAction"); menuHolder.addSeparator("popup/"); menuHolder.addAction(copyLinkToClipboardAction, "popup/copyLinkToClipboardAction"); menuHolder.addAction(copyCoordinatesToClipboardAction, "popup/copyCoordinatesToClipboardAction"); menuHolder.updateMenus(mPopupMenu, "popup/"); /* * map location context menu */ menuHolder.addAction(new EditNodeInContextMenu(), "contextPopup/editNodeInContextMenu"); menuHolder.addAction(new RemoveNodeLocationInContextMenu(), "contextPopup/RemoveNodeLocationInContextMenu"); menuHolder.addAction(new SelectNodeInContextMenu(), "contextPopup/SelectNodeInContextMenu"); menuHolder.addAction(new SelectNodeAndCloseInContextMenu(), "contextPopup/SelectNodeAndCloseInContextMenu"); menuHolder.addSeparator("contextPopup/"); menuHolder.addAction(new ShowNodeMapInContextMenu(), "contextPopup/showNodeMapInContextMenu"); menuHolder.addAction(maxmimalZoomToCursorAction, "contextPopup/maxmimalZoomToCursorAction"); menuHolder.addSeparator("contextPopup/"); menuHolder.addAction(copyLinkToClipboardAction, "contextPopup/copyLinkToClipboardAction"); menuHolder.addAction(new AddMapPictureToNode(), "contextPopup/addPictureToNode"); menuHolder.updateMenus(getContextPopupMenu(), "contextPopup/"); menuHolder.addAction(maxmimalZoomToCursorAction, "searchPopup/maxmimalZoomToCursorAction"); menuHolder.updateMenus(getSearchPopupMenu(), "searchPopup/"); mMapDialog.addKeyListener(this); // Tools.addFocusPrintTimer(); } public void addAccelerator(JMenuItem menuItem, String key) { String keyProp = mMindMapController.getFrame().getProperty(key); KeyStroke keyStroke = KeyStroke.getKeyStroke(keyProp); // menuItem.setAccelerator(keyStroke); menuItem.getAction().putValue(Action.ACCELERATOR_KEY, keyStroke); } /** * @param pSelected * @return */ protected MapNodePositionHolderBase placeNode(MindMapNode pSelected) { Coordinate cursorPosition = getMap().getCursorPosition(); Coordinate position = map.getPosition(); int zoom = map.getZoom(); return placeNodeAt(pSelected, cursorPosition, position, zoom); } protected MapNodePositionHolderBase placeNodeAt(MindMapNode pSelected, Coordinate cursorPosition, Coordinate position, int zoom) { MapNodePositionHolder hook = MapNodePositionHolder.getHook(pSelected); if (hook == null) { hook = addHookToNode(pSelected); } if (hook != null) { // set parameters: String tileSource = getTileSourceAsString(); hook.changePosition(cursorPosition, position, zoom, tileSource); } else { logger.warning("Hook not found although it was recently added. Node was " + pSelected); } return hook; } public String getTileSourceAsString() { String tileSource = getTileSourceName(getTileSource()); return tileSource; } public TileSource getTileSource() { return getMap().getTileController().getTileSource(); } public void removeNodePosition(MindMapNode selected) { MapNodePositionHolderBase hook = MapNodePositionHolder .getHook(selected); if (hook != null) { // double add == remove addHookToNode(selected); } } /** */ public void showSelectedNodes() { MindMapNode selected = mMindMapController.getSelected(); List selecteds = mMindMapController.getSelecteds(); if (selecteds.size() == 1) { MapNodePositionHolder hook = MapNodePositionHolder .getHook(selected); if (hook != null) { showNode(hook); } return; } // find common center. Code adapted from JMapViewer. int x_min = Integer.MAX_VALUE; int y_min = Integer.MAX_VALUE; int x_max = Integer.MIN_VALUE; int y_max = Integer.MIN_VALUE; int mapZoomMax = getMaxZoom(); for (Iterator it = selecteds.iterator(); it.hasNext();) { MindMapNode node = (MindMapNode) it.next(); MapNodePositionHolder hook = MapNodePositionHolder.getHook(node); if (hook != null) { int x = OsmMercator.LonToX(hook.getPosition().getLon(), mapZoomMax); int y = OsmMercator.LatToY(hook.getPosition().getLat(), mapZoomMax); x_max = Math.max(x_max, x); y_max = Math.max(y_max, y); x_min = Math.min(x_min, x); y_min = Math.min(y_min, y); if (node == selected) { setCursorPosition(hook.getPosition()); changeTileSource(hook.getTileSource(), map); } } } int height = Math.max(0, getMap().getHeight()); int width = Math.max(0, getMap().getWidth()); int newZoom = mapZoomMax; int x = x_max - x_min; int y = y_max - y_min; while (x > width || y > height) { newZoom--; x >>= 1; y >>= 1; } x = x_min + (x_max - x_min) / 2; y = y_min + (y_max - y_min) / 2; int z = 1 << (mapZoomMax - newZoom); x /= z; y /= z; getMap().setDisplayPosition(x, y, newZoom); } public int getMaxZoom() { return getTileSource().getMaxZoom(); } public void showNode(MapNodePositionHolder hook) { int zoom = hook.getZoom(); changeTileSource(hook.getTileSource(), map); setCursorPosition(hook, zoom); } public void setCursorPosition(MapNodePositionHolder hook, int zoom) { Coordinate position = hook.getPosition(); Coordinate mapCenter = hook.getMapCenter(); setZoom(zoom); if (mapCenter != null) { // move map: logger.fine("Set display position to " + mapCenter + " and cursor to " + position + " and zoom " + zoom + " where max zoom is " + getMaxZoom()); map.setDisplayPositionByLatLon(mapCenter.getLat(), mapCenter.getLon(), zoom); } setCursorPosition(position); } /** * Sets the cursor to the specified position and moves the display, such * that the cursor is visible. */ protected void setCursorPosition(Coordinate position) { getMap().setCursorPosition(position); // is the cursor now visible and the zoom correct? if not, display it // directly. if (map.getMapPosition(position, true) == null) { map.setDisplayPositionByLatLon(position.getLat(), position.getLon(), map.getZoom()); } storeMapPosition(position); for (Iterator it = mCursorPositionListeners.iterator(); it.hasNext();) { CursorPositionListener listener = (CursorPositionListener) it .next(); listener.cursorPositionChanged(position); } } /** * Sets the zoom. */ protected void setZoom(int zoom) { if (zoom > getMaxZoom()) { zoom = getMaxZoom(); } if (zoom == 0) { zoom = map.getZoom(); } map.setZoom(zoom); } /** * @param pTileSource * @param pMap * if found, the map tile source is set. Set null, if you don't * want this. * @return null, if the string is not found. */ public static TileSource changeTileSource(String pTileSource, JMapViewer pMap) { logger.fine("Searching for tile source " + pTileSource); TileSourceStore tileSource = getTileSourceByName(pTileSource); if (tileSource != null && pMap != null) { pMap.setTileSource(tileSource.mTileSource); return tileSource.mTileSource; } return null; } public static TileSourceStore getTileSourceByName(String sourceName) { for (int i = 0; i < sTileSources.length; i++) { TileSourceStore source = sTileSources[i]; if (Tools.safeEquals(getTileSourceName(source.mTileSource), sourceName)) { logger.fine("Found tile source " + source); return source; } } return null; } public static String getTileSourceName(TileSource source) { return source.getClass().getName(); } public MapNodePositionHolder addHookToNode(MindMapNode selected) { MapNodePositionHolder hook; List selecteds = Tools.getVectorWithSingleElement(selected); mMindMapController.addHook(selected, selecteds, MapNodePositionHolderBase.NODE_MAP_HOOK_NAME, null); hook = MapNodePositionHolder.getHook(selected); return hook; } /** * Translate String * * @param pString * @return */ private String getText(String pString) { return mMindMapController.getText(pString); } public void mouseDragged(MouseEvent e) { if (!mMovementEnabled || !(isMoving || isMapNodeMoving || mIsRectangularSelect)) return; if (isMapNodeMoving) { lastDragPoint = e.getPoint(); int diffx = 0; int diffy = 0; if (e.getX() < SCROLL_MARGIN) { diffx = -SCROLL_PIXEL_AMOUNT; } if (map.getWidth() - e.getX() < SCROLL_MARGIN) { diffx = SCROLL_PIXEL_AMOUNT; } if (e.getY() < SCROLL_MARGIN) { diffy = -SCROLL_PIXEL_AMOUNT; } if (map.getHeight() - e.getY() < SCROLL_MARGIN) { diffy = SCROLL_PIXEL_AMOUNT; } map.moveMap(diffx, diffy); return; } if (mIsRectangularSelect) { // Actualize second point of rectangle. getMap().setRectangular(mRectangularStart, getCoordinateFromMouseEvent(e)); getMap().setDrawRectangular(true); getMap().repaint(); return; } // Is only the selected mouse button pressed? if ((e.getModifiersEx() & MOUSE_BUTTONS_MASK) == movementMouseButtonMask) { moveMapOnDrag(e); } } public void moveMapOnDrag(MouseEvent e) { Point p = e.getPoint(); if (lastDragPoint != null) { int diffx = lastDragPoint.x - p.x; int diffy = lastDragPoint.y - p.y; map.moveMap(diffx, diffy); // System.out.println("Move to " + map.getPosition() + // " with zoom " + map.getZoom() ); } lastDragPoint = p; } public void mouseClicked(MouseEvent e) { if (!mClickEnabled) { return; } if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { // on double click: new node. newNode(e); return; } // is button 1? if (e.getButton() == MouseEvent.BUTTON1 || Tools.isMacOsX() && e.getModifiersEx() == MAC_MOUSE_BUTTON1_MASK) { setCursorPosition(e); } } private void setMouseControl(boolean pEnable) { setMovementEnabled(pEnable); setWheelZoomEnabled(pEnable); setClickEnabled(pEnable); } /** * @param pEvent * : location */ private void newNode(MouseEvent pEvent) { final MindMapNode targetNode = mMindMapController.getSelected(); final MindMapNode newNode = insertNewNode(targetNode); final NodeView nodeView = mMindMapController.getNodeView(newNode); mMindMapController.select(nodeView); // inline editing: mMindMapController.setBlocked(true); setMouseControl(false); Point point = pEvent.getPoint(); Tools.convertPointToAncestor((Component) pEvent.getSource(), point, map); storeMapPosition(getMap().getCursorPosition()); MapEditTextFieldControl editControl = new MapEditTextFieldControl( nodeView, newNode, targetNode, false); EditNodeTextField textfield = new MapEditNoteTextField(nodeView, "", null, mMindMapController, editControl, map, point); textfield.show(); } public MindMapNode insertNewNode(final MindMapNode targetNode) { int childPosition; MindMapNode parent; if (targetNode.isRoot()) { parent = targetNode; childPosition = 0; } else { // new sibling: parent = targetNode.getParentNode(); childPosition = parent.getChildPosition(targetNode); childPosition++; } final MindMapNode newNode = mMindMapController.addNewNode(parent, childPosition, targetNode.isLeft()); return newNode; } /** * @param pPositionHolder * @param pEvent * : location */ private void editNode(MapNodePositionHolder pPositionHolder, MouseEvent pEvent) { final MindMapNode editNode = pPositionHolder.getNode(); final NodeView nodeView = mMindMapController.getNodeView(editNode); if (nodeView == null) { return; } mMindMapController.select(nodeView); // inline editing: mMindMapController.setBlocked(true); setMouseControl(false); Point point = pEvent.getPoint(); Tools.convertPointToAncestor((Component) pEvent.getSource(), point, map); MapEditTextFieldControl editControl = new MapEditTextFieldControl( nodeView, editNode, editNode, true); EditNodeTextField textfield = new MapEditNoteTextField(nodeView, editNode.getText(), null, mMindMapController, editControl, map, point); textfield.show(); } public void setCursorPosition(MouseEvent e) { final Coordinate coordinates = map.getPosition(e.getPoint()); setCursorPosition(coordinates); } public void mousePressed(MouseEvent e) { if (!mClickEnabled) { return; } showPopupMenu(e); if (e.isConsumed()) { return; } if (e.getButton() == movementMouseButton || (Tools.isMacOsX() && e.getModifiersEx() == MAC_MOUSE_BUTTON1_MASK)) { if (e.isShiftDown()) { // rectangular select: mIsRectangularSelect = true; mRectangularStart = getCoordinateFromMouseEvent(e); logger.fine("Starting rect on " + mRectangularStart); return; } // detect collision with map marker: MapMarkerBase mapMarker = checkHit(e); if (mapMarker instanceof MapMarkerLocation) { MapNodePositionHolder posHolder = ((MapMarkerLocation) mapMarker) .getNodePositionHolder(); mDragStartingPoint = new Point(e.getPoint()); correctPointByMapCenter(mDragStartingPoint); isMapNodeMoving = true; mMapNodeMovingSource = posHolder; setCursor(Cursor.MOVE_CURSOR, true); return; } lastDragPoint = null; isMoving = true; } } protected void correctPointByMapCenter(Point dragStartingPoint) { Point center = getMap().getCenter(); dragStartingPoint.translate(center.x, center.y); } public MapMarkerBase checkHit(MouseEvent e) { // check for hit on map marker: for (Iterator it = map.getMapMarkerList().iterator(); it.hasNext();) { MapMarkerBase location = (MapMarkerBase) it.next(); Coordinate locationC = location.getCoordinate(); Point locationXY = map.getMapPosition(locationC, true); if (locationXY == null) { continue; } boolean checkHitResult = location.checkHit(e.getX() - locationXY.x, e.getY() - locationXY.y); logger.fine("Checking for hit for location " + location + " at location " + locationXY + " to event " + e.getX() + " and " + e.getY() + " is " + checkHitResult); if (checkHitResult) { return location; } } return null; } public Coordinate getCoordinateFromMouseEvent(MouseEvent e) { Coordinate mousePosition = map .getPosition(new Point(e.getX(), e.getY())); return mousePosition; } /** * @param e * event. */ private void showPopupMenu(MouseEvent e) { if (e.isPopupTrigger()) { JPopupMenu popupmenu = getPopupMenu(); // check for hit on map marker: MapMarkerBase mapMarker = checkHit(e); if (mapMarker instanceof MapMarkerLocation) { MapNodePositionHolder posHolder = ((MapMarkerLocation) mapMarker) .getNodePositionHolder(); mCurrentPopupPositionHolder = posHolder; setCursorPosition(posHolder.getPosition()); getContextPopupMenu() .show(e.getComponent(), e.getX(), e.getY()); e.consume(); return; } if (mapMarker instanceof MapSearchMarkerLocation) { MapSearchMarkerLocation location = (MapSearchMarkerLocation) mapMarker; setCursorPosition(location.getCoordinate()); getSearchPopupMenu().show(e.getComponent(), e.getX(), e.getY()); e.consume(); return; } mCurrentPopupPositionHolder = null; if (popupmenu != null) { setCursorPosition(e); popupmenu.show(e.getComponent(), e.getX(), e.getY()); e.consume(); } } } /** * listener, that blocks the controler if the menu is active (PN) Take care! * This listener is also used for modelpopups (as for graphical links). */ private class ControllerPopupMenuListener implements PopupMenuListener { public void popupMenuWillBecomeVisible(PopupMenuEvent e) { setMouseControl(false); // block controller } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { setMouseControl(true); // unblock controller } public void popupMenuCanceled(PopupMenuEvent e) { setMouseControl(true); // unblock controller } } /** * Take care! This listener is also used for modelpopups (as for graphical * links). */ protected final ControllerPopupMenuListener popupListenerSingleton = new ControllerPopupMenuListener(); private MouseEvent mTimerMouseEvent; private Action mZoomInAction; private Action mZoomOutAction; private MoveForwardAction mMoveForwardAction; private MoveBackwardAction mMoveBackwardAction; JMenuBar mMenuBar; private long mWheelZoomLastTime = 0; private Vector mCursorPositionListeners = new Vector(); private JPopupMenu mSearchPopupMenu; public void mouseReleased(MouseEvent e) { if (!mClickEnabled) { return; } showPopupMenu(e); if (e.isConsumed()) { return; } if (e.getButton() == movementMouseButton || Tools.isMacOsX() && e.getButton() == MouseEvent.BUTTON1) { final Coordinate coordinates = getCoordinateFromMouseEvent(e); if (isMapNodeMoving) { // check for minimal drag distance: Point currentPoint = new Point(e.getPoint()); correctPointByMapCenter(currentPoint); if (mDragStartingPoint.distance(currentPoint) > MapMarkerLocation.CIRCLE_RADIUS) { Coordinate mousePosition = coordinates; mMapNodeMovingSource.changePosition(mousePosition, map.getPosition(), map.getZoom(), getTileSourceAsString()); } else { // select the node (single click) MindMapNode node = mMapNodeMovingSource.getNode(); if (e.isShiftDown()) { Vector sel = new Vector( mMindMapController.getSelecteds()); if (sel.contains(node)) { // remove: sel.remove(node); node = mMindMapController.getSelected(); } else { sel.add(node); } mMindMapController.select(node, sel); } else { selectNode(node); } } mMapNodeMovingSource = null; setCursor(Cursor.DEFAULT_CURSOR, false); } if (mIsRectangularSelect) { // gather all locations and select them: Vector mapNodePositionHolders = new Vector(); // take only those elements in the correct rectangle: Rectangle r = getMap().getRectangle(mRectangularStart, coordinates); if (r != null) { MindMapNode last = null; for (Iterator it = mMapHook.getMapNodePositionHolders() .iterator(); it.hasNext();) { MapNodePositionHolder holder = (MapNodePositionHolder) it .next(); Coordinate pointPosition = holder.getPosition(); Point mapPosition = getMap().getMapPosition( pointPosition, true); if (mapPosition != null && r.contains(mapPosition)) { // ok mapNodePositionHolders.add(holder.getNode()); last = holder.getNode(); } } if (last != null) { // ie. at least one found: mMindMapController.select(last, mapNodePositionHolders); } } } getMap().setDrawRectangular(false); mIsRectangularSelect = false; mRectangularStart = null; isMapNodeMoving = false; if (lastDragPoint != null) { storeMapPosition(coordinates); } lastDragPoint = null; isMoving = false; } } protected void storeMapPosition(final Coordinate coordinates) { final PositionHolder holder = new PositionHolder(coordinates.getLat(), coordinates.getLon(), getMap().getZoom()); final Vector positionHolderVector = getPositionHolderVector(); if (getPositionHolderIndex() >= 0) { // check for equalness PositionHolder currentPosition = (PositionHolder) positionHolderVector .get(getPositionHolderIndex()); if (currentPosition.equals(holder)) { return; } } // if position is not at the end, the locations in front are deleted. while (getPositionHolderIndex() < positionHolderVector.size() - 1) { positionHolderVector.remove(positionHolderVector.size() - 1); } logger.fine("Storing position " + holder + " at index " + getPositionHolderIndex()); positionHolderVector.insertElementAt(holder, getPositionHolderIndex() + 1); setPositionHolderIndex(getPositionHolderIndex() + 1); // assure that max size is below limit. while (positionHolderVector.size() >= POSITION_HOLDER_LIMIT && getPositionHolderIndex() > 0) { setPositionHolderIndex(Math.max(getPositionHolderIndex() - 1, 0)); positionHolderVector.remove(0); } // update actions mMoveForwardAction.setEnabled(mMoveForwardAction.isEnabled()); mMoveBackwardAction.setEnabled(mMoveBackwardAction.isEnabled()); } protected void setCursor(int defaultCursor, boolean pVisible) { Component glassPane = getGlassPane(); glassPane.setCursor(Cursor.getPredefinedCursor(defaultCursor)); glassPane.setVisible(pVisible); } public Component getGlassPane() { return map.getRootPane().getGlassPane(); } public void mouseWheelMoved(MouseWheelEvent e) { if (mWheelZoomEnabled) { /* * This is problematic under Mac as the zoom is too fast. First * idea: looking for the last time the zoom was changed. It must not * be changed within 100ms again. Moreover, limit the rotation * number. */ if (System.currentTimeMillis() - mWheelZoomLastTime >= WHEEL_ZOOM_MINIMAL_TIME_BETWEEN_CHANGES) { int wheelRotation = e.getWheelRotation(); if (Math.abs(wheelRotation) > 2) { wheelRotation = (int) (2 * Math.signum(wheelRotation)); } map.setZoom(map.getZoom() - wheelRotation, e.getPoint()); mWheelZoomLastTime = System.currentTimeMillis(); } } } public boolean isMovementEnabled() { return mMovementEnabled; } /** * Enables or disables that the map pane can be moved using the mouse. * * @param movementEnabled */ public void setMovementEnabled(boolean movementEnabled) { this.mMovementEnabled = movementEnabled; } public int getMovementMouseButton() { return movementMouseButton; } public JPopupMenu getPopupMenu() { return mPopupMenu; } public JPopupMenu getContextPopupMenu() { if (mContextPopupMenu == null) { mContextPopupMenu = new JPopupMenu(); mContextPopupMenu.addPopupMenuListener(popupListenerSingleton); } return mContextPopupMenu; } public JPopupMenu getSearchPopupMenu() { if (mSearchPopupMenu == null) { mSearchPopupMenu = new JPopupMenu(); mSearchPopupMenu.addPopupMenuListener(popupListenerSingleton); } return mSearchPopupMenu; } /** * Sets the mouse button that is used for moving the map. Possible values * are: * <ul> * <li>{@link MouseEvent#BUTTON1} (left mouse button)</li> * <li>{@link MouseEvent#BUTTON2} (middle mouse button)</li> * <li>{@link MouseEvent#BUTTON3} (right mouse button)</li> * </ul> * * @param movementMouseButton */ public void setMovementMouseButton(int movementMouseButton) { this.movementMouseButton = movementMouseButton; switch (movementMouseButton) { case MouseEvent.BUTTON1: movementMouseButtonMask = MouseEvent.BUTTON1_DOWN_MASK; break; case MouseEvent.BUTTON2: movementMouseButtonMask = MouseEvent.BUTTON2_DOWN_MASK; break; case MouseEvent.BUTTON3: movementMouseButtonMask = MouseEvent.BUTTON3_DOWN_MASK; break; default: throw new RuntimeException("Unsupported button"); } } public boolean isWheelZoomEnabled() { return mWheelZoomEnabled; } public void setWheelZoomEnabled(boolean wheelZoomEnabled) { this.mWheelZoomEnabled = wheelZoomEnabled; } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseMoved(MouseEvent e) { if (!mMovementEnabled) { return; } // Mac OSX simulates with ctrl + mouse 1 the second mouse button hence // no dragging events get fired. // if (Tools.isMacOsX()) { if (isMapNodeMoving) { lastDragPoint = e.getPoint(); return; } // Is only the selected mouse button pressed? if (isMoving && e.getModifiersEx() == 0 /* MouseEvent.CTRL_DOWN_MASK */) { moveMapOnDrag(e); return; } } // no move events, thus the cursor is just moving. mMouseHitsNodeTimer.restart(); mTimerMouseEvent = e; } /** * Action handler for search result handling. * * @param pPlace */ public void setCursorPosition(Place pPlace) { map.setDisplayPositionByLatLon(pPlace.getLat(), pPlace.getLon(), map.getZoom()); Coordinate cursorPosition = new Coordinate(pPlace.getLat(), pPlace.getLon()); setCursorPosition(cursorPosition); } /** * @return true, if ok, false if error. */ public boolean search(MapDialog.ResultTableModel dataModel, JTable mResultTable, String mSearchText, Color mTableOriginalBackgroundColor) { // Display hour glass boolean returnValue = true; setCursor(Cursor.WAIT_CURSOR, true); try { dataModel.clear(); // doesn't work due to event thread... mResultTable.setBackground(Color.GRAY); Searchresults results = getSearchResults(mSearchText); if (results == null) { mResultTable.setBackground(Color.RED); } else { for (Iterator it = results.getListPlaceList().iterator(); it .hasNext();) { Place place = (Place) it.next(); logger.fine("Found place " + place.getDisplayName()); // error handling, if the query wasn't successful. if (Tools.safeEquals("ERROR", place.getOsmType())) { mResultTable.setBackground(Color.RED); returnValue = false; } else if (Tools.safeEquals("WARNING", place.getOsmType())) { mResultTable.setBackground(Color.YELLOW); returnValue = false; } else { mResultTable.setBackground(Color.WHITE); mResultTable .setBackground(mTableOriginalBackgroundColor); } dataModel.addPlace(place); } } } catch (Exception e) { freemind.main.Resources.getInstance().logException(e); returnValue = false; } setCursor(Cursor.DEFAULT_CURSOR, false); return returnValue; } public Reversegeocode getReverseLookup(Coordinate pCoordinate, int pZoom) { StringBuilder b = new StringBuilder(); b.append("http://nominatim.openstreetmap.org/reverse?format=xml&email=christianfoltin%40users.sourceforge.net&addressdetails=0"); //$NON-NLS-1$ b.append("&accept-language=").append(Locale.getDefault().getLanguage()); //$NON-NLS-1$ b.append("&lat="); b.append(pCoordinate.getLat()); b.append("&lon="); b.append(pCoordinate.getLon()); b.append("&zoom="); b.append(pZoom); try { String result = wget(b); Reversegeocode reversegeocode = (Reversegeocode) XmlBindingTools .getInstance().unMarshall(result); return reversegeocode; } catch (Exception e) { freemind.main.Resources.getInstance().logException(e); } return null; } /** * @param pText * @return */ public Searchresults getSearchResults(String pText) { String result = "unknown"; Searchresults results = new Searchresults(); StringBuilder b = new StringBuilder(); boolean limitSearchToRegion = mMapHook.isLimitSearchToRegion(); try { if (true) { b.append("http://nominatim.openstreetmap.org/search/?email=christianfoltin%40users.sourceforge.net&q="); //$NON-NLS-1$ b.append(URLEncoder.encode(pText, "UTF-8")); b.append("&format=xml&limit=30&accept-language=").append(Locale.getDefault().getLanguage()); //$NON-NLS-1$ if (limitSearchToRegion) { Coordinate topLeftCorner = getMap().getPosition(0, 0); Coordinate bottomRightCorner = getMap().getPosition( getMap().getWidth(), getMap().getHeight()); b.append("&viewbox="); b.append(topLeftCorner.getLon()); b.append(","); b.append(topLeftCorner.getLat()); b.append(","); b.append(bottomRightCorner.getLon()); b.append(","); b.append(bottomRightCorner.getLat()); b.append("&bounded=1"); } result = wget(b); } else { // only for offline testing: result = XML_VERSION_1_0_ENCODING_UTF_8 + "<searchresults timestamp=\"Tue, 08 Nov 11 22:49:54 -0500\" attribution=\"Data Copyright OpenStreetMap Contributors, Some Rights Reserved. CC-BY-SA 2.0.\" querystring=\"innsbruck\" polygon=\"false\" exclude_place_ids=\"228452,25664166,26135863,25440203\" more_url=\"http://open.mapquestapi.com/nominatim/v1/search?format=xml&exclude_place_ids=228452,25664166,26135863,25440203&accept-language=&q=innsbruck\">\n" + " <place place_id=\"228452\" osm_type=\"node\" osm_id=\"34840064\" place_rank=\"16\" boundingbox=\"47.2554266357,47.2754304504,11.3827679062,11.4027688599\" lat=\"47.2654296\" lon=\"11.3927685\" display_name=\"Innsbruck, Bezirk Innsbruck-Stadt, Innsbruck-Stadt, Tirol, Österreich, Europe\" class=\"place\" type=\"city\" icon=\"http://open.mapquestapi.com/nominatim/v1/images/mapicons/poi_place_city.p.20.png\"/>\n" + " <place place_id=\"25664166\" osm_type=\"way\" osm_id=\"18869490\" place_rank=\"27\" boundingbox=\"43.5348739624023,43.5354156494141,-71.1319198608398,-71.1316146850586\" lat=\"43.5351336524196\" lon=\"-71.1317853486877\" display_name=\"Innsbruck, New Durham, Strafford County, New Hampshire, United States of America\" class=\"highway\" type=\"service\"/>\n" + " <place place_id=\"26135863\" osm_type=\"way\" osm_id=\"18777572\" place_rank=\"27\" boundingbox=\"38.6950759887695,38.6965446472168,-91.1586227416992,-91.1520233154297\" lat=\"38.6957456083531\" lon=\"-91.1552550683042\" display_name=\"Innsbruck, Warren, Aspenhoff, Warren County, Missouri, United States of America\" class=\"highway\" type=\"service\"/>\n" + " <place place_id=\"25440203\" osm_type=\"way\" osm_id=\"18869491\" place_rank=\"27\" boundingbox=\"43.5335311889648,43.5358810424805,-71.1356735229492,-71.1316146850586\" lat=\"43.5341678362733\" lon=\"-71.1338615946084\" display_name=\"Innsbruck, New Durham, Strafford County, New Hampshire, 03855, United States of America\" class=\"highway\" type=\"service\"/>\n" + "</searchresults>"; result = "<?xml version=\"1.0\" encoding=\"UTF-8\"" + " ?><searchresults timestamp='Wed, 29 Aug" + " 12 06:33:22 +0100' attribution='Data Co" + "pyright OpenStreetMap Contributors, Some" + " Rights Reserved. CC-BY-SA 2.0.' queryst" + "ring='bäckerei' polygon='false' exclude_" + "place_ids='2323884,1350101,7261519,17658" + "198,16228926,7825940,8072208,16133988,51" + "52777,7708711,16471512,7844042,12267468," + "6699146,7114466,6856494,856383,9874163,7" + "135888,868611,11403029,6568269,16118527," + "7540110,11628259,1339026,19587330,115253" + "72,11534612,11748035' more_url='http://n" + "ominatim.openstreetmap.org/search?format" + "=xml&exclude_place_ids=2323884,13501" + "01,7261519,17658198,16228926,7825940,807" + "2208,16133988,5152777,7708711,16471512,7" + "844042,12267468,6699146,7114466,6856494," + "856383,9874163,7135888,868611,11403029,6" + "568269,16118527,7540110,11628259,1339026" + ",19587330,11525372,11534612,11748035&" + ";accept-language=de&viewbox=13.24470" + "5200195312%2C52.43435075954755%2C13.3324" + "2416381836%2C52.461762311435194&q=b%" + "C3%A4ckerei'><place place_id='2323884' o" + "sm_type='node' osm_id='352983574' place_" + "rank='30' boundingbox=\"52.443815460205," + "52.463819274902,13.313097229004,13.33309" + "8182678\" lat='52.4538175' lon='13.32309" + "74' display_name='Bäckerei Mälzer, Schüt" + "zenstraße, Steglitz, Steglitz-Zehlendorf" + ", Berlin, 12165, Deutschland' class='sho" + "p' type='bakery' icon='http://nominatim." + "openstreetmap.org/images/mapicons/shoppi" + "ng_bakery.p.20.png'/><place place_id='13" + "50101' osm_type='node' osm_id='298794800" + "' place_rank='30' boundingbox=\"52.43134" + "9029541,52.451352844238,13.282660713196," + "13.30266166687\" lat='52.4413499' lon='1" + "3.2926616' display_name='Bäckerei Bertra" + "m, 27, Curtiusstraße, Lichterfelde, Steg" + "litz-Zehlendorf, Berlin, 12205, Deutschl" + "and' class='shop' type='bakery' icon='ht" + "tp://nominatim.openstreetmap.org/images/" + "mapicons/shopping_bakery.p.20.png'/><pla" + "ce place_id='7261519' osm_type='node' os" + "m_id='792690678' place_rank='30' boundin" + "gbox=\"52.434942474365,52.454946289062,1" + "3.282605400085,13.30260635376\" lat='52." + "444945' lon='13.292606' display_name='Kn" + "ese-Bäckerei, Knesebeckstraße, Lichterfe" + "lde, Steglitz-Zehlendorf, Berlin, 12205," + " Deutschland' class='shop' type='bakery'" + " icon='http://nominatim.openstreetmap.or" + "g/images/mapicons/shopping_bakery.p.20.p" + "ng'/><place place_id='17658198' osm_type" + "='node' osm_id='1655185388' place_rank='" + "30' boundingbox=\"52.426340332031,52.446" + "344146728,13.256445159912,13.27644611358" + "6\" lat='52.4363419' lon='13.2664454' di" + "splay_name='Bäckerei Strauch, Berliner S" + "traße, Zehlendorf, Steglitz-Zehlendorf, " + "Berlin, 14169, Deutschland' class='shop'" + " type='bakery' icon='http://nominatim.op" + "enstreetmap.org/images/mapicons/shopping" + "_bakery.p.20.png'/><place place_id='1622" + "8926' osm_type='node' osm_id='1455112119" + "' place_rank='30' boundingbox=\"52.43713" + "973999,52.457143554687,13.296548118591,1" + "3.316549072266\" lat='52.4471403' lon='1" + "3.3065482' display_name='Bäckerei Hillma" + "nn, 52, Moltkestraße, Lichterfelde, Steg" + "litz-Zehlendorf, Berlin, 12203, Deutschl" + "and' class='shop' type='bakery' icon='ht" + "tp://nominatim.openstreetmap.org/images/" + "mapicons/shopping_bakery.p.20.png'/><pla" + "ce place_id='7825940' osm_type='node' os" + "m_id='803776974' place_rank='30' boundin" + "gbox=\"52.447733154297,52.467736968994,1" + "3.280044784546,13.30004573822\" lat='52." + "4577338' lon='13.2900455' display_name='" + "Wiener Feinbäcker Heberer, Brümmerstraße" + ", Dahlem, Steglitz-Zehlendorf, Berlin, 1" + "4195, Deutschland' class='shop' type='ba" + "kery' icon='http://nominatim.openstreetm" + "ap.org/images/mapicons/shopping_bakery.p" + ".20.png'/><place place_id='8072208' osm_" + "type='node' osm_id='814072915' place_ran" + "k='30' boundingbox=\"52.430979003906,52." + "450982818603,13.279904594421,13.29990554" + "8096\" lat='52.4409802' lon='13.2899047'" + " display_name='Brotmeisterei Steinecke, " + "36-38, Curtiusstraße, Lichterfelde, Steg" + "litz-Zehlendorf, Berlin, 12205, Deutschl" + "and' class='shop' type='bakery' icon='ht" + "tp://nominatim.openstreetmap.org/images/" + "mapicons/shopping_bakery.p.20.png'/><pla" + "ce place_id='16133988' osm_type='node' o" + "sm_id='1391486692' place_rank='30' bound" + "ingbox=\"52.44658493042,52.466588745117," + "13.310922851563,13.330923805237\" lat='5" + "2.4565867' lon='13.3209229' display_name" + "='Wiedemann, Albrechtstraße, Steglitz, S" + "teglitz-Zehlendorf, Berlin, 12165, Deuts" + "chland' class='shop' type='bakery' icon=" + "'http://nominatim.openstreetmap.org/imag" + "es/mapicons/shopping_bakery.p.20.png'/><" + "place place_id='5152777' osm_type='node'" + " osm_id='570034727' place_rank='30' boun" + "dingbox=\"52.441808929443,52.46181274414" + "1,13.320470085144,13.340471038818\" lat=" + "'52.4518101' lon='13.3304701' display_na" + "me='Konditorei Rabien, Klingsorstraße, S" + "teglitz, Steglitz-Zehlendorf, Berlin, 12" + "167, Deutschland' class='shop' type='bak" + "ery' icon='http://nominatim.openstreetma" + "p.org/images/mapicons/shopping_bakery.p." + "20.png'/></searchresults>"; // result = XML_VERSION_1_0_ENCODING_UTF_8 // + // "<searchresults timestamp=\"Tue, 08 Nov 11 22:49:54 -0500\" attribution=\"Data Copyright OpenStreetMap Contributors, Some Rights Reserved. CC-BY-SA 2.0.\" querystring=\"innsbruck\" polygon=\"false\" exclude_place_ids=\"228452,25664166,26135863,25440203\" more_url=\"http://open.mapquestapi.com/nominatim/v1/search?format=xml&exclude_place_ids=228452,25664166,26135863,25440203&accept-language=&q=innsbruck\">\n" // + "</searchresults>"; } results = (Searchresults) XmlBindingTools.getInstance().unMarshall( result); if (results == null) { logger.warning(result + " can't be parsed"); } } catch (Exception e) { logger.fine("Searching for " + b.toString() + " gave an error"); final String errorString = e.toString(); freemind.main.Resources.getInstance().logException(e); logger.warning("Result was " + result); results.addPlace(getErrorPlace(errorString, "ERROR")); } if (results.getListPlaceList().isEmpty()) { String textId; if (limitSearchToRegion) { textId = "plugins.map.FreeMindMapController.LimitedSearchWithoutResult"; } else { textId = "plugins.map.FreeMindMapController.SearchWithoutResult"; } Object[] messageArguments = { pText }; MessageFormat formatter = new MessageFormat( mMindMapController.getText(textId)); String message = formatter.format(messageArguments); results.addPlace(getErrorPlace(message, "WARNING")); } return results; } public String wget(StringBuilder b) throws MalformedURLException, IOException, UnsupportedEncodingException { String result; mMindMapController.getFrame().setWaitingCursor(true); try { logger.fine("Searching for " + b.toString()); URL url = new URL(b.toString()); URLConnection urlConnection = url.openConnection(); if (Tools.isAboveJava4()) { urlConnection.setConnectTimeout(Resources.getInstance() .getIntProperty(OSM_NOMINATIM_CONNECT_TIMEOUT_IN_MS, 10000)); urlConnection .setReadTimeout(Resources.getInstance().getIntProperty( OSM_NOMINATIM_READ_TIMEOUT_IN_MS, 30000)); } InputStream urlStream = urlConnection.getInputStream(); result = Tools.getFile(new InputStreamReader(urlStream)); result = new String(result.getBytes(), "UTF-8"); logger.fine(result + " was received for search " + b); } finally { mMindMapController.getFrame().setWaitingCursor(false); } return result; } protected Place getErrorPlace(final String errorString, String errorLevel) { Place place = new Place(); place.setDisplayName(errorString); place.setOsmType(errorLevel); Coordinate cursorPosition = getMap().getCursorPosition(); place.setLat(cursorPosition.getLat()); place.setLon(cursorPosition.getLon()); return place; } public boolean isClickEnabled() { return mClickEnabled; } public void setClickEnabled(boolean pClickEnabled) { mClickEnabled = pClickEnabled; } public static TileSourceStore[] getmTileSources() { return sTileSources; } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent pE) { String statusText = ""; // here, we look wether or not the cursor is above a node. MapMarkerBase mapMarker = checkHit(mTimerMouseEvent); if (mapMarker instanceof MapMarkerLocation) { MapNodePositionHolder posHolder = ((MapMarkerLocation) mapMarker) .getNodePositionHolder(); logger.fine("Looking for hit on node " + posHolder); if (posHolder != null) { statusText = Tools.getNodeTextHierarchy(posHolder.getNode(), mMapHook.getMindMapController()) + ". "; } } // calculate the distance to the cursor Coordinate coordinate = getCoordinateFromMouseEvent(mTimerMouseEvent); Coordinate cursorPosition = getMap().getCursorPosition(); double distance = OsmMercator.getDistance(coordinate.getLat(), coordinate.getLon(), cursorPosition.getLat(), cursorPosition.getLon()) / 1000.0; Object[] messageArguments = { new Double(distance), new Double(coordinate.getLat()), new Double(coordinate.getLon()) }; MessageFormat formatter = new MessageFormat( mMindMapController.getText("plugins/map/MapDialog_Distance")); String message = formatter.format(messageArguments); statusText += message; mMapHook.getStatusLabel().setText(statusText); } protected void selectContextMenuNode() { MindMapNode node = mCurrentPopupPositionHolder.getNode(); selectNode(node); } protected void selectNode(MindMapNode node) { mMindMapController.select(node, Tools.getVectorWithSingleElement(node)); } public static String getLink(MapNodePositionHolder hook) { String tileSource = hook.getTileSource(); Coordinate position = hook.getPosition(); Coordinate mapCenter = hook.getMapCenter(); int zoom = hook.getZoom(); return getLink(tileSource, position, mapCenter, zoom); } public static String getLink(String tileSource, Coordinate position, Coordinate mapCenter, int zoom) { String layer = "M"; TileSourceStore tileSourceByName = FreeMindMapController .getTileSourceByName(tileSource); if (tileSourceByName != null) { layer = tileSourceByName.mLayerName; } /* * The embedded link would work for IE, too. But it is not easy to * configure as a bounding box is necessary. It reads like * osm.org/export/embed.html?bbox=... */ String link = "http://www.openstreetmap.org/?" + "mlat=" + position.getLat() + "&mlon=" + position.getLon() + "&lat=" + mapCenter.getLat() + "&lon=" + mapCenter.getLon() + "&zoom=" + zoom + "&layers=" + layer; return link; } public void keyTyped(KeyEvent pEvent) { if (mMapHook.isSearchBarVisible()) { return; } Action[] specialKeyActions = { mZoomInAction, mZoomOutAction }; Tools.invokeActionsToKeyboardLayoutDependantCharacters(pEvent, specialKeyActions, mMapDialog); if (!pEvent.isConsumed() && !pEvent.isActionKey() && (Character.isLetter(pEvent.getKeyChar())) && ((pEvent.getModifiers() & MODIFIERS_WITHOUT_SHIFT) == 0)) { // open search bar and process event. // logger.info("Key event processed: " + pEvent); mMapHook.toggleSearchBar(pEvent); mMapHook.setSingleSearch(); } } public void keyReleased(KeyEvent pEvent) { } public void keyPressed(KeyEvent pEvent) { if (mMapHook.isSearchBarVisible()) { return; } int modifiers = pEvent.getModifiers() & MODIFIERS_WITHOUT_SHIFT; // only plain of shifted cursor keys are consumed here. if (modifiers == 0) { int dx = MOVE_PIXEL_AMOUNT; int dy = MOVE_PIXEL_AMOUNT; if (pEvent.isShiftDown()) { dx = (int) (map.getWidth() * PAGE_DOWN_FACTOR); dy = (int) (map.getHeight() * PAGE_DOWN_FACTOR); } switch (pEvent.getKeyCode()) { case KeyEvent.VK_LEFT: map.moveMap(-dx, 0); pEvent.consume(); break; case KeyEvent.VK_RIGHT: map.moveMap(dx, 0); pEvent.consume(); break; case KeyEvent.VK_UP: map.moveMap(0, -dy); pEvent.consume(); break; case KeyEvent.VK_DOWN: map.moveMap(0, dy); pEvent.consume(); break; } } } public Vector getPositionHolderVector() { return mPositionHolderVector; } public int getPositionHolderIndex() { return mPositionHolderIndex; } /** * @param positionHolderIndex * @return true, if positionHolderIndex is ok. */ public boolean checkPositionHolderIndex(int positionHolderIndex) { return !(positionHolderIndex < -1 || positionHolderIndex >= mPositionHolderVector .size()); } public void setPositionHolderIndex(int positionHolderIndex) { if (!checkPositionHolderIndex(positionHolderIndex)) { throw new IllegalArgumentException("Index out of range " + positionHolderIndex); } mPositionHolderIndex = positionHolderIndex; } /** * @param pListener */ public void addCursorPositionListener(CursorPositionListener pListener) { mCursorPositionListeners.add(pListener); } /** * @param pSelected * @param pPlace */ public void addNode(MindMapNode pSelected, Place pPlace) { addNode(pSelected, pPlace.getDisplayName(), pPlace.getLat(), pPlace.getLon()); } public void addNode(MindMapNode pSelected, String pText, double lat, double lon) { final MindMapNode targetNode = pSelected; final MindMapNode newNode = insertNewNode(targetNode); mMindMapController.setNodeText(newNode, pText); placeNodeAt(newNode, new Coordinate(lat, lon), map.getPosition(), map.getZoom()); } private class AddSearchResultsToMapTask extends FreeMindTask { private Place[] mPlaces; public AddSearchResultsToMapTask(int[] pSelectedRows) { super(mMapDialog, pSelectedRows.length, MAP_DIALOG_PROGRESS_MESSAGE); // deep copy mPlaces = new Place[pSelectedRows.length]; for (int i = 0; i < pSelectedRows.length; i++) { mPlaces[i] = mMapHook.getPlace(pSelectedRows[i]); } } /* * (non-Javadoc) * * @see freemind.common.FreeMindTask#processAction() */ protected boolean processAction() throws Exception { int selIndex = getRounds(); final Place place = mPlaces[selIndex]; mProgressDescription = new ProgressDescription( MAP_DIALOG_ADD_PLACES, new Object[] { place.getDisplayName() }); final MindMapNode selected = getMindMapController().getSelected(); EventQueue.invokeAndWait(new Runnable() { public void run() { addNode(selected, place); } }); return true; } } public void addSearchResultsToMap(int[] pSelectedRows) { AddSearchResultsToMapTask task = new AddSearchResultsToMapTask( pSelectedRows); task.start(); } private ModeController getMindMapController() { return mMindMapController; } }