Java tutorial
/** * OrbisGIS is a java GIS application dedicated to research in GIScience. * OrbisGIS is developed by the GIS group of the DECIDE team of the * Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>. * * The GIS group of the DECIDE team is located at : * * Laboratoire Lab-STICC CNRS UMR 6285 * Equipe DECIDE * UNIVERSIT DE BRETAGNE-SUD * Institut Universitaire de Technologie de Vannes * 8, Rue Montaigne - BP 561 56017 Vannes Cedex * * OrbisGIS is distributed under GPL 3 license. * * Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488) * Copyright (C) 2015-2016 CNRS (Lab-STICC UMR CNRS 6285) * * This file is part of OrbisGIS. * * OrbisGIS 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 3 of the License, or (at your option) any later * version. * * OrbisGIS 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 * OrbisGIS. If not, see <http://www.gnu.org/licenses/>. * * For more information, please consult: <http://www.orbisgis.org/> * or contact directly: * info_at_ orbisgis.org */ package org.orbisgis.mapeditor.map; import com.vividsolutions.jts.geom.Envelope; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.MouseMotionListener; import java.awt.geom.Point2D; import java.beans.EventHandler; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLayeredPane; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.TreeExpansionListener; import org.apache.commons.io.FilenameUtils; import org.orbisgis.commons.progress.SwingWorkerPM; import org.orbisgis.core_export.MapImageWriter; import org.orbisgis.corejdbc.DataManager; import org.orbisgis.coremap.layerModel.ILayer; import org.orbisgis.coremap.layerModel.LayerException; import org.orbisgis.coremap.layerModel.MapContext; import org.orbisgis.coremap.map.MapTransform; import org.orbisgis.coremap.map.TransformListener; import org.orbisgis.coremap.process.ZoomToSelection; import org.orbisgis.coremap.renderer.ResultSetProviderFactory; import org.orbisgis.editorjdbc.jobs.CreateSourceFromSelection; import org.orbisgis.mapeditor.map.ext.MapEditorAction; import org.orbisgis.mapeditor.map.icons.MapEditorIcons; import org.orbisgis.mapeditor.map.jobs.ReadMapContextJob; import org.orbisgis.mapeditor.map.mapsManager.MapsManager; import org.orbisgis.mapeditor.map.mapsManager.TreeLeafMapContextFile; import org.orbisgis.mapeditor.map.mapsManager.TreeLeafMapElement; import org.orbisgis.mapeditor.map.tool.ToolManager; import org.orbisgis.mapeditor.map.tool.TransitionException; import org.orbisgis.mapeditor.map.toolbar.ActionAutomaton; import org.orbisgis.mapeditor.map.tools.*; import org.orbisgis.mapeditorapi.MapEditorExtension; import org.orbisgis.mapeditorapi.MapElement; import org.orbisgis.commons.progress.NullProgressMonitor; import org.orbisgis.commons.progress.ProgressMonitor; import org.orbisgis.mapeditorapi.MapsManagerData; import org.orbisgis.sif.UIFactory; import org.orbisgis.sif.components.ColorPicker; import org.orbisgis.sif.components.SaveFilePanel; import org.orbisgis.sif.edition.EditorDockable; import org.orbisgis.sif.multiInputPanel.*; import org.orbisgis.sif.components.actions.ActionCommands; import org.orbisgis.sif.components.actions.ActionDockingListener; import org.orbisgis.sif.edition.EditableTransferListener; import org.orbisgis.sif.components.actions.DefaultAction; import org.orbisgis.sif.docking.DockingPanelParameters; import org.orbisgis.sif.edition.EditableElement; import org.orbisgis.editorjdbc.EditableSource; import org.orbisgis.sif.edition.EditorManager; import org.orbisgis.wkguiapi.ViewWorkspace; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xnap.commons.i18n.I18n; import org.xnap.commons.i18n.I18nFactory; /** * The Map Editor Panel */ @Component(service = { EditorDockable.class, MapEditorExtension.class }) public class MapEditor extends JPanel implements TransformListener, MapEditorExtension { private static final I18n I18N = I18nFactory.getI18n(MapEditor.class); private static final Logger GUILOGGER = LoggerFactory.getLogger("gui." + MapEditor.class); //The UID must be incremented when the serialization is not compatible with the new version of this class private static final long serialVersionUID = 1L; private MapControl mapControl = new MapControl(); private MapContext mapContext = null; private MapElement mapElement; private DockingPanelParameters dockingPanelParameters; private MapTransferHandler dragDropHandler; private MapStatusBar mapStatusBar = new MapStatusBar(); //This timer will fetch the cursor component coordinates //Then translate to the map coordinates and send it to //the MapStatusBar private AtomicBoolean processingCursor = new AtomicBoolean(false); private Point lastCursorPosition = new Point(); private AtomicBoolean initialised = new AtomicBoolean(false); private MapsManager mapsManager; private JLayeredPane layeredPane = new JLayeredPane(); private ComponentListener sizeListener = EventHandler.create(ComponentListener.class, this, "updateMapControlSize", null, "componentResized"); private PropertyChangeListener modificationListener = EventHandler.create(PropertyChangeListener.class, this, "onMapModified"); private PropertyChangeListener activeLayerListener = EventHandler.create(PropertyChangeListener.class, this, "onActiveLayerChange", ""); private ActionCommands actions = new ActionCommands(); private MapEditorPersistence mapEditorPersistence = new MapEditorPersistence(); private DataManager dataManager; private ViewWorkspace viewWorkspace; private EditorManager editorManager; private Map<ResultSetProviderFactory, Action> rsFactories = new HashMap<>(); private ExecutorService executorService; private boolean userChangedWidth = false; private boolean userChangedHeight = false; /** * Constructor */ public MapEditor() { super(new BorderLayout()); } private void execute(SwingWorker swingWorker) { if (executorService != null) { executorService.execute(swingWorker); } else { swingWorker.execute(); } } @Reference public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; mapControl.setExecutorService(executorService); } public void unsetExecutorService(ExecutorService executorService) { this.executorService = null; mapControl.setExecutorService(null); } @Reference public void setViewWorkspace(ViewWorkspace viewWorkspace) { this.viewWorkspace = viewWorkspace; } @Reference public void setEditorManager(EditorManager editorManager) { this.editorManager = editorManager; } @Reference public void setDataManager(DataManager dataManager) { this.dataManager = dataManager; } public void unsetViewWorkspace(ViewWorkspace viewWorkspace) { this.viewWorkspace = null; } public void unsetEditorManager(EditorManager editorManager) { this.editorManager = null; } public void unsetDataManager(DataManager dataManager) { this.dataManager = null; } @Activate public void activate() { this.mapsManager = new MapsManager(viewWorkspace.getMapContextPath(), dataManager, editorManager); dockingPanelParameters = new DockingPanelParameters(); dockingPanelParameters.setName("map_editor"); updateMapLabel(); dockingPanelParameters.setTitleIcon(MapEditorIcons.getIcon("map")); dockingPanelParameters.setMinimizable(false); dockingPanelParameters.setExternalizable(false); dockingPanelParameters.setCloseable(false); dockingPanelParameters.setLayout(mapEditorPersistence); dockingPanelParameters.setVisible(true); layeredPane.add(mapControl, 1); layeredPane.add(mapsManager, 0); mapsManager.setVisible(false); mapsManager.setMapsManagerPersistence(mapEditorPersistence.getMapsManagerPersistence()); // when the layout is loaded, this editor will load the map element linked with this layout mapEditorPersistence.addPropertyChangeListener(MapEditorPersistence.PROP_DEFAULTMAPCONTEXT, EventHandler.create(PropertyChangeListener.class, this, "onSerialisationMapChange")); add(layeredPane, BorderLayout.CENTER); add(mapStatusBar, BorderLayout.PAGE_END); //Declare Tools of Map Editors //Add the tools in the docking Panel title createActions(); dockingPanelParameters.setDockActions(actions.getActions()); // Tools that will be created later will also be set in the docking panel // thanks to this listener actions.addPropertyChangeListener(new ActionDockingListener(dockingPanelParameters)); //Set the Drop target dragDropHandler = new MapTransferHandler(); this.setTransferHandler(dragDropHandler); } @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) public void addMapEditorActionFactory(MapEditorAction mapEditorAction) { actions.addActionFactory(mapEditorAction, this); } public void removeMapEditorActionFactory(MapEditorAction mapEditorAction) { actions.removeActionFactory(mapEditorAction); } @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) public void addResultSetProviderFactory(ResultSetProviderFactory resultSetProviderFactory) { Action rsAction = new DefaultAction("RSF_" + resultSetProviderFactory.getName(), resultSetProviderFactory.getName(), null, EventHandler.create(ActionListener.class, this, "onChangeRendererData", "")).setMenuGroup(true) .setParent(MapEditorAction.A_DATA_PROVIDERS) .setButtonGroup(MapEditorAction.TOGGLE_GROUP_DATA_PROVIDERS); rsFactories.put(resultSetProviderFactory, rsAction); actions.addAction(rsAction); } public void removeResultSetProviderFactory(ResultSetProviderFactory resultSetProviderFactory) { actions.removeAction(rsFactories.remove(resultSetProviderFactory)); } public void onChangeRendererData(ActionEvent ae) { } private void updateMapLabel() { if (mapElement == null) { dockingPanelParameters.setTitle(I18N.tr("Map")); } else { if (mapElement.isModified()) { dockingPanelParameters .setTitle(I18N.tr("Map Editor \"{0}\" [Modified]", mapElement.getMapContext().getTitle())); } else { dockingPanelParameters .setTitle(I18N.tr("Map Editor \"{0}\"", mapElement.getMapContext().getTitle())); } } } /** * The user update the scale field * @param pce update event * @throws PropertyVetoException If the property entered is incorrect */ public void onUserSetScaleDenominator(PropertyChangeEvent pce) throws PropertyVetoException { long newScale = (Long) pce.getNewValue(); if (newScale < 1) { throw new PropertyVetoException( I18N.tr("The value of the scale denominator must be equal or greater than 1"), pce); } mapControl.getMapTransform().setScaleDenominator(newScale); } /** * Notifies this component that it now has a parent component. When this * method is invoked, the chain of parent components is set up with * KeyboardAction event listeners. */ @Override public void addNotify() { super.addNotify(); if (!initialised.getAndSet(true)) { addComponentListener(sizeListener); // Read the default map context file initMapContext(); //Register listener dragDropHandler.getTransferEditableEvent().addListener(this, EventHandler.create(EditableTransferListener.class, this, "onDropEditable", "editableList")); mapControl.addMouseMotionListener( EventHandler.create(MouseMotionListener.class, this, "onMouseMove", "point", "mouseMoved")); mapStatusBar.addVetoableChangeListener(MapStatusBar.PROP_USER_DEFINED_SCALE_DENOMINATOR, EventHandler.create(VetoableChangeListener.class, this, "onUserSetScaleDenominator", "")); // When the tree is expanded update the manager size mapsManager.getTree().addComponentListener(sizeListener); mapsManager.getTree().addTreeExpansionListener( EventHandler.create(TreeExpansionListener.class, this, "updateMapControlSize")); } } private void initMapContext() { File serialisedMapContextPath = new File(viewWorkspace.getMapContextPath() + File.separator, mapEditorPersistence.getDefaultMapContext()); if (!serialisedMapContextPath.exists()) { createDefaultMapContext(dataManager); } else { TreeLeafMapElement defaultMap = (TreeLeafMapElement) mapsManager.getFactoryManager() .create(serialisedMapContextPath); try { MapElement mapElementToLoad = defaultMap.getMapElement(new NullProgressMonitor(), dataManager); execute(new ReadMapContextJob(mapElementToLoad, editorManager)); } catch (IllegalArgumentException ex) { //Map XML is invalid GUILOGGER.warn(I18N.tr("Fail to load the map context, starting with an empty map context"), ex); createDefaultMapContext(dataManager); } } } /** * Create the default map context, create it if the map folder is empty */ private void createDefaultMapContext(DataManager dataManager) { //Load the map context File mapContextFolder = new File(viewWorkspace.getMapContextPath()); if (!mapContextFolder.exists()) { mapContextFolder.mkdir(); } File mapContextFile = new File(mapContextFolder, I18N.tr("MyMap.ows")); if (!mapContextFile.exists()) { //Create an empty map context TreeLeafMapContextFile.createEmptyMapContext(mapContextFile, dataManager); } MapElement editableMap = new MapElement(mapContextFile, dataManager); execute(new ReadMapContextJob(editableMap, editorManager)); } /** * Compute the appropriate components bounds for MapControl * and MapsManager and apply theses bounds */ public void updateMapControlSize() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { doUpdateMapControlSize(); } }); } private void doUpdateMapControlSize() { mapControl.setBounds(0, 0, layeredPane.getWidth(), layeredPane.getHeight()); if (mapsManager.isVisible()) { Dimension mapsManagerPreferredSize = mapsManager.getMinimalComponentDimension(); int hPos = layeredPane.getWidth() - Math.min(mapsManagerPreferredSize.width, layeredPane.getWidth()); mapsManager.setBounds(hPos, 0, Math.min(mapsManagerPreferredSize.width, layeredPane.getWidth()), Math.min(mapsManagerPreferredSize.height, layeredPane.getHeight())); mapsManager.revalidate(); } } /** * The user Drop a list of Editable * @param editableList Load the editable elements in the current map context */ public void onDropEditable(EditableElement[] editableList) { //Load the layers in the background execute(new DropDataSourceProcess(editableList, mapContext, editorManager)); } /** * Load a new map context * @param element Editable to load */ private void loadMap(MapElement element) { MapElement oldMapElement = mapElement; ToolManager oldToolManager = getToolManager(); removeListeners(); mapElement = element; if (element != null) { try { mapContext = (MapContext) element.getObject(); mapContext.addPropertyChangeListener(MapContext.PROP_ACTIVELAYER, activeLayerListener); mapControl.setMapContext(mapContext); mapControl.getMapTransform().setExtent(mapContext.getBoundingBox()); mapControl.setElement(this); mapControl.initMapControl(new PanTool()); // Update the default map context path with the relative path URI rootDir = (new File(viewWorkspace.getMapContextPath() + File.separator)).toURI(); String relative = rootDir.relativize(element.getMapContextFile().toURI()).getPath(); mapEditorPersistence.setDefaultMapContext(relative); // Set the loaded map hint to the MapCatalog mapsManager.setLoadedMap(element.getMapContextFile()); // Update the editor label with the new editable name updateMapLabel(); mapElement.addPropertyChangeListener(MapElement.PROP_MODIFIED, modificationListener); repaint(); } catch (IllegalStateException | TransitionException ex) { GUILOGGER.error(ex.getLocalizedMessage(), ex); } } else { // Load null MapElement mapControl.setMapContext(null); } firePropertyChange(PROP_TOOL_MANAGER, oldToolManager, getToolManager()); firePropertyChange(PROP_MAP_ELEMENT, oldMapElement, mapElement); } /** * The DefaultMapContext property of {@link MapEditorPersistence} has been updated, load this map */ public void onSerialisationMapChange() { String fileName = mapEditorPersistence.getDefaultMapContext(); File mapFilePath = new File(viewWorkspace.getMapContextPath(), fileName); if (!mapFilePath.exists()) { return; } if (mapElement != null && mapFilePath.equals(mapElement.getMapContextFile())) { return; } MapElement mapElement = new MapElement(mapFilePath, dataManager); execute(new ReadMapContextJob(mapElement, editorManager)); } /** * MouseMove event on the MapControl * @param mousePosition x,y position of the event relative to the MapControl component. */ public void onMouseMove(Point mousePosition) { lastCursorPosition.setLocation(mousePosition); if (mapElement != null) { if (!processingCursor.getAndSet(true)) { (new CursorCoordinateProcessing(mapStatusBar, processingCursor, mapControl.getMapTransform(), lastCursorPosition)).execute(); } } } /** * Free MapEditor resources **/ public void dispose() { removeListeners(); getMapControl().closing(); loadMap(null); } @Override public MapElement getMapElement() { return mapElement; } /** * MapEditor tools declaration */ private void createActions() { // Cache control actions.addAction(new DefaultAction(MapEditorAction.A_MAP_CLEAR_CACHE, I18N.tr("Refresh"), MapEditorIcons.getIcon("refresh"), EventHandler.create(ActionListener.class, this, "onClearCache"))); // Navigation tools actions.addAction(new ActionAutomaton(MapEditorAction.A_ZOOM_IN, new ZoomInTool(), this) .setLogicalGroup("navigation")); actions.addAction(new ActionAutomaton(MapEditorAction.A_ZOOM_OUT, new ZoomOutTool(), this) .setLogicalGroup("navigation")); actions.addAction(new DefaultAction(MapEditorAction.A_FULL_EXTENT, I18N.tr("Full extent"), MapEditorIcons.getIcon("zoom_extent"), EventHandler.create(ActionListener.class, this, "onFullExtent")) .setToolTipText(I18N.tr("Zoom to show all geometries")).setLogicalGroup("navigation")); actions.addAction( new ActionAutomaton(MapEditorAction.A_PAN, new PanTool(), this).setLogicalGroup("navigation")); // Selection tools actions.addAction(new ActionAutomaton(MapEditorAction.A_INFO_TOOL, new InfoTool(), this) .addTrackedMapContextProperty(MapContext.PROP_SELECTEDLAYERS) .addTrackedMapContextProperty(MapContext.PROP_SELECTEDSTYLES).setLogicalGroup("selection")); actions.addAction(new ActionAutomaton(MapEditorAction.A_SELECTION, new SelectionTool(), this) .addTrackedMapContextProperty(MapContext.PROP_SELECTEDLAYERS) .addTrackedMapContextProperty(MapContext.PROP_SELECTEDSTYLES).setLogicalGroup("selection")); //Clear selection group actions.addAction( new DefaultAction(MapEditorAction.A_CLEAR_SELECTION_GROUP, I18N.tr("Clear selection tools")) .setMenuGroup(true)); actions.addAction(new DefaultAction(MapEditorAction.A_CLEAR_ALL_SELECTION, I18N.tr("Clear all selection"), MapEditorIcons.getIcon("edit-clear_all"), EventHandler.create(ActionListener.class, this, "onClearAllSelection")) .setToolTipText(I18N.tr("Clear all selected geometries of all layers")) .setParent(MapEditorAction.A_CLEAR_SELECTION_GROUP)); actions.addAction(new DefaultAction(MapEditorAction.A_CLEAR_LAYER_SELECTION, I18N.tr("Clear selected layers"), MapEditorIcons.getIcon("edit-clear"), EventHandler.create(ActionListener.class, this, "onClearLayerSelection")) .setToolTipText(I18N.tr("Clear all selected geometries of the selected layers")) .setParent(MapEditorAction.A_CLEAR_SELECTION_GROUP)); //Zoom to selection group actions.addAction(new DefaultAction(MapEditorAction.A_ZOOM_SELECTION_GROUP, I18N.tr("Zoom to tools")) .setMenuGroup(true)); actions.addAction(new DefaultAction(MapEditorAction.A_ZOOM_ALL_SELECTION, I18N.tr("Zoom to all selection"), MapEditorIcons.getIcon("zoom_selected_all"), EventHandler.create(ActionListener.class, this, "onZoomToAllSelection")) .setToolTipText(I18N.tr("Zoom to all selected geometries")) .setParent(MapEditorAction.A_ZOOM_SELECTION_GROUP)); actions.addAction(new DefaultAction(MapEditorAction.A_ZOOM_LAYER_SELECTION, I18N.tr("Zoom to layer selection"), MapEditorIcons.getIcon("zoom_selected"), EventHandler.create(ActionListener.class, this, "onZoomToLayerSelection")) .setToolTipText(I18N.tr("Zoom to selected geometries of the selected layers")) .setParent(MapEditorAction.A_ZOOM_SELECTION_GROUP)); actions.addAction(new DefaultAction(MapEditorAction.A_DATA_SOURCE_FROM_SELECTION, I18N.tr("Create datasource from selection"), MapEditorIcons.getIcon("table_go"), EventHandler.create(ActionListener.class, this, "onCreateDataSourceFromSelection")) .setToolTipText(I18N.tr("Create a datasource from the current selection")) .setLogicalGroup("selection")); // Measure tools actions.addAction( new DefaultAction(MapEditorAction.A_MEASURE_GROUP, I18N.tr("Mesure tools")).setMenuGroup(true)); actions.addAction(new ActionAutomaton(MapEditorAction.A_MEASURE_LINE, new MesureLineTool(), this) .setParent(MapEditorAction.A_MEASURE_GROUP)); actions.addAction(new ActionAutomaton(MapEditorAction.A_MEASURE_POLYGON, new MesurePolygonTool(), this) .setParent(MapEditorAction.A_MEASURE_GROUP)); actions.addAction(new ActionAutomaton(MapEditorAction.A_COMPASS, new CompassTool(), this) .setParent(MapEditorAction.A_MEASURE_GROUP)); // Drawing tools actions.addAction( new DefaultAction(MapEditorAction.A_DRAWING_GROUP, I18N.tr("Graphic tools")).setMenuGroup(true)); actions.addAction(new ActionAutomaton(MapEditorAction.A_FENCE, new FencePolygonTool(), this) .setParent(MapEditorAction.A_DRAWING_GROUP)); actions.addAction( new ActionAutomaton(MapEditorAction.A_PICK_COORDINATES, new PickCoordinatesPointTool(), this) .setParent(MapEditorAction.A_DRAWING_GROUP)); // Maps manager actions.addAction(new DefaultAction(MapEditorAction.A_MAP_TREE, I18N.tr("Maps manager"), MapEditorIcons.getIcon("map_manager"), EventHandler.create(ActionListener.class, this, "onShowHideMapsTree")) .setToolTipText(I18N.tr("Show/Hide Maps Manager"))); actions.addAction(new DefaultAction(MapEditorAction.A_MAP_EXPORT_IMAGE, I18N.tr("Export map as image"), MapEditorIcons.getIcon("export_image"), EventHandler.create(ActionListener.class, this, "onExportMapRendering")) .setToolTipText(I18N.tr("Export image as file"))); // Parameters //actions.addAction(new DefaultAction(MapEditorAction.A_PARAMETERS,I18N.tr("Configuration"), // MapEditorIcons.getIcon("config")).setMenuGroup(true)); //actions.addAction(new DefaultAction(MapEditorAction.A_DATA_PROVIDERS,I18N.tr("Data query"), // MapEditorIcons.getIcon("table_go")).setMenuGroup(true).setParent(MapEditorAction.A_PARAMETERS)); } /** * @return The manager of docking actions. */ public ActionCommands getActionCommands() { return actions; } /** * User want to see table updates on MapEditor */ public void onClearCache() { mapControl.clearCache(); // Redraw mapControl.invalidateImage(); } /** * User click on the Show/Hide maps tree */ public void onShowHideMapsTree() { if (!mapsManager.isVisible()) { mapsManager.setVisible(true); updateMapControlSize(); } else { mapsManager.setVisible(false); } } /** * The user click on the button Full Extent */ public void onFullExtent() { mapControl.getMapTransform().setExtent(mapContext.getLayerModel().getEnvelope()); } /** * The use want to export the rendering into a file. */ public void onExportMapRendering() { // Show Dialog to select image size final String WIDTH_T = "width"; final String HEIGHT_T = "height"; final String RATIO_CHECKBOX_T = "ratio checkbox"; final String TRANSPARENT_BACKGROUND_T = "background"; final String DPI_T = "dpi"; final int textWidth = 8; final MultiInputPanel inputPanel = new MultiInputPanel(I18N.tr("Export parameters")); inputPanel.addInput(TRANSPARENT_BACKGROUND_T, "", "True", new CheckBoxChoice(true, "<html>" + I18N.tr("Transparent\nbackground") + "</html>")); inputPanel.addInput(DPI_T, I18N.tr("DPI"), String.valueOf((int) (MapImageWriter.MILLIMETERS_BY_INCH / MapImageWriter.DEFAULT_PIXEL_SIZE)), new TextBoxType(textWidth)); TextBoxType tbWidth = new TextBoxType(textWidth); inputPanel.addInput(WIDTH_T, I18N.tr("Width (pixels)"), String.valueOf(mapControl.getImage().getWidth()), tbWidth); TextBoxType tbHeight = new TextBoxType(textWidth); inputPanel.addInput(HEIGHT_T, I18N.tr("Height (pixels)"), String.valueOf(mapControl.getImage().getHeight()), tbHeight); tbHeight.getComponent().addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { userChangedHeight = true; } @Override public void focusLost(FocusEvent e) { updateWidth(); } private void updateWidth() { if (userChangedHeight) { if (inputPanel.getInput(RATIO_CHECKBOX_T).equals("true")) { // Change image width to keep ratio final String heightString = inputPanel.getInput(HEIGHT_T); if (!heightString.isEmpty()) { try { final Envelope adjExtent = mapControl.getMapTransform().getAdjustedExtent(); final double ratio = adjExtent.getWidth() / adjExtent.getHeight(); final int height = Integer.parseInt(heightString); final long newWidth = Math.round(height * ratio); inputPanel.setValue(WIDTH_T, String.valueOf(newWidth)); } catch (NumberFormatException e) { } } } } userChangedWidth = false; } }); tbWidth.getComponent().addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { userChangedWidth = true; } @Override public void focusLost(FocusEvent e) { updateHeight(); } private void updateHeight() { if (userChangedWidth) { if (inputPanel.getInput(RATIO_CHECKBOX_T).equals("true")) { // Change image height to keep ratio final String widthString = inputPanel.getInput(WIDTH_T); if (!widthString.isEmpty()) { try { final Envelope adjExtent = mapControl.getMapTransform().getAdjustedExtent(); final double ratio = adjExtent.getHeight() / adjExtent.getWidth(); final int width = Integer.parseInt(widthString); final long newHeight = Math.round(width * ratio); inputPanel.setValue(HEIGHT_T, String.valueOf(newHeight)); } catch (NumberFormatException e) { } } } } userChangedHeight = false; } }); inputPanel.addInput(RATIO_CHECKBOX_T, "", new CheckBoxChoice(true, I18N.tr("Keep ratio"))); inputPanel.addValidation(new MIPValidationInteger(WIDTH_T, I18N.tr("Width (pixels)"))); inputPanel.addValidation(new MIPValidationInteger(HEIGHT_T, I18N.tr("Height (pixels)"))); inputPanel.addValidation(new MIPValidationInteger(DPI_T, I18N.tr("DPI"))); JButton refreshButton = new JButton(I18N.tr("Reset extent")); refreshButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { inputPanel.setValue(WIDTH_T, String.valueOf(mapControl.getImage().getWidth())); inputPanel.setValue(HEIGHT_T, String.valueOf(mapControl.getImage().getHeight())); } }); // Show the dialog and get the user's choice. int userChoice = JOptionPane.showOptionDialog(this, inputPanel.getComponent(), I18N.tr("Export map as image"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, MapEditorIcons.getIcon("map_catalog"), new Object[] { I18N.tr("OK"), I18N.tr("Cancel"), refreshButton }, null); // If the user clicked OK, then show the save image dialog. if (userChoice == JOptionPane.OK_OPTION) { MapImageWriter mapImageWriter = new MapImageWriter(mapContext.getLayerModel()); mapImageWriter .setPixelSize(MapImageWriter.MILLIMETERS_BY_INCH / Double.valueOf(inputPanel.getInput(DPI_T))); // If the user want a background color, let him choose one if (!Boolean.valueOf(inputPanel.getInput(TRANSPARENT_BACKGROUND_T))) { ColorPicker colorPicker = new ColorPicker(Color.white); if (!UIFactory.showDialog(colorPicker, true, true)) { return; } mapImageWriter.setBackgroundColor(colorPicker.getColor()); } // Save the picture in which location final SaveFilePanel outfilePanel = new SaveFilePanel("MapEditor.ExportInFile", I18N.tr("Save the map as image : " + mapContext.getTitle())); outfilePanel.addFilter("png", I18N.tr("Portable Network Graphics")); outfilePanel.addFilter("tiff", I18N.tr("Tagged Image File Format")); outfilePanel.addFilter("jpg", I18N.tr("Joint Photographic Experts Group")); outfilePanel.addFilter("pdf", I18N.tr("Portable Document Format")); outfilePanel.loadState(); // Load last use path // Show save into dialog if (UIFactory.showDialog(outfilePanel, true, true)) { File outFile = outfilePanel.getSelectedFile(); String fileName = FilenameUtils.getExtension(outFile.getName()); if (fileName.equalsIgnoreCase("png")) { mapImageWriter.setFormat(MapImageWriter.Format.PNG); } else if (fileName.equalsIgnoreCase("jpg")) { mapImageWriter.setFormat(MapImageWriter.Format.JPEG); } else if (fileName.equalsIgnoreCase("pdf")) { mapImageWriter.setFormat(MapImageWriter.Format.PDF); } else { mapImageWriter.setFormat(MapImageWriter.Format.TIFF); } mapImageWriter.setBoundingBox(mapContext.getBoundingBox()); int width = Integer.valueOf(inputPanel.getInput(WIDTH_T)); int height = Integer.valueOf(inputPanel.getInput(HEIGHT_T)); mapImageWriter.setWidth(width); mapImageWriter.setHeight(height); execute(new ExportRenderingIntoFile(mapImageWriter, outFile)); } } } /** * The edited layer of the loaded Map Context has been set. * @param evt Event raised by the MapContext */ public void onActiveLayerChange(PropertyChangeEvent evt) { if (getToolManager() != null) { getToolManager().activeLayerChanged(evt); getToolManager().checkToolStatus(); } } /** * The user click on the button clear selection. * The selected layers are cleaned. */ public void onClearLayerSelection() { ILayer[] selectedLayers = getMapControl().getToolManager().getSelectedLayerAndStyle(); // Loop through all selected layers. if (selectedLayers == null || selectedLayers.length == 0) { GUILOGGER.warn(I18N.tr("Please select a layer or a style in the TOC.")); } else { for (ILayer layer : selectedLayers) { if (!layer.acceptsChilds()) { if (!layer.getSelection().isEmpty()) { layer.setSelection(new HashSet<Long>()); } } } } } /** * The user click on the button, all selection are cleaned in the layers */ public void onClearAllSelection() { for (ILayer layer : mapContext.getLayers()) { if (!layer.acceptsChilds()) { if (!layer.getSelection().isEmpty()) { layer.setSelection(new HashSet<Long>()); } } } } /** * The user click on the button Zoom to selection */ public void onZoomToAllSelection() { ArrayList<ILayer> selectedLayers = new ArrayList<ILayer>(); for (ILayer iLayer : mapContext.getLayers()) { if (!iLayer.getSelection().isEmpty()) { selectedLayers.add(iLayer); } } if (!selectedLayers.isEmpty()) { execute(new ZoomToSelection(mapContext, selectedLayers.toArray(new ILayer[selectedLayers.size()]))); } else { GUILOGGER.warn(I18N.tr("There is any selection available.")); } } /** * Zoom on selected geometries of each selected layers */ public void onZoomToLayerSelection() { ILayer[] selectedLayers = getMapControl().getToolManager().getSelectedLayerAndStyle(); // Loop through all selected layers. if (selectedLayers == null || selectedLayers.length == 0) { GUILOGGER.warn(I18N.tr("Please select a layer or a style in the TOC")); } else { execute(new ZoomToSelection(mapContext, selectedLayers)); } } /** * The user can export the selected features into a new datasource */ public void onCreateDataSourceFromSelection() { // Get the selected layer(s) ILayer[] selectedLayers = getMapControl().getToolManager().getSelectedLayerAndStyle(); // Loop through all selected layers. if (selectedLayers == null || selectedLayers.length == 0) { GUILOGGER.warn(I18N.tr("No layers are selected.")); } else { for (ILayer layer : selectedLayers) { Set<Long> selection = layer.getSelection(); // If there is a nonempty selection, then ask the user to name it. if (!selection.isEmpty()) { try { String newName = CreateSourceFromSelection.showNewNameDialog(this, dataManager.getDataSource(), layer.getTableReference()); // If newName is not null, then the user clicked OK and // entered a valid name. if (newName != null) { execute(new CreateSourceFromSelection(dataManager.getDataSource(), selection, layer.getTableReference(), newName)); } } catch (SQLException ex) { GUILOGGER.error(ex.getLocalizedMessage(), ex); } } else { GUILOGGER.warn(I18N.tr("Layer {0} has no selected geometries.", layer.getName())); } } } } /** * Give information on the behaviour of this panel related to the current * docking system * @return The panel parameter instance */ @Override public DockingPanelParameters getDockingParameters() { return dockingPanelParameters; } @Override public JComponent getComponent() { return this; } /** * @return {@link MapControl} linked to this {@code MapEditor}. */ public MapControl getMapControl() { return mapControl; } @Override public void extentChanged(Envelope oldExtent, MapTransform mapTransform) { //Update the scale in the MapEditor status bar mapStatusBar.setScaleDenominator(mapTransform.getScaleDenominator()); } @Override public void imageSizeChanged(int oldWidth, int oldHeight, MapTransform mapTransform) { //do nothing } @Override public boolean match(EditableElement editableElement) { return editableElement instanceof MapElement; } @Override public EditableElement getEditableElement() { return mapElement; } @Override public void setEditableElement(EditableElement editableElement) { if (editableElement instanceof MapElement) { loadMap((MapElement) editableElement); } } /** * Remove the listeners on the current loaded document */ private void removeListeners() { if (mapElement != null) { mapElement.removePropertyChangeListener(modificationListener); mapElement.getMapContext().removePropertyChangeListener(activeLayerListener); } if (mapControl != null && mapControl.getToolManager() != null) { mapControl.getToolManager().removeToolListener(null); } } /** * The editable modified state is switching */ public void onMapModified() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateMapLabel(); mapsManager.updateDiskTree(); if (getToolManager() != null) { getToolManager().updateToolsStatus(); } } }); } public ToolManager getToolManager() { return mapControl.getToolManager(); } @Override public MapTransform getMapTransform() { return mapControl.getMapTransform(); } /** * This task draw the image into an external file */ private static class ExportRenderingIntoFile extends SwingWorkerPM { private MapImageWriter mapImageWriter; private File outFile; private ExportRenderingIntoFile(MapImageWriter mapImageWriter, File outFile) { this.mapImageWriter = mapImageWriter; this.outFile = outFile; setTaskName(I18N.tr("Drawing into file")); } @Override protected Object doInBackground() throws Exception { try { FileOutputStream fileOutputStream = new FileOutputStream(outFile); mapImageWriter.write(fileOutputStream, this.getProgressMonitor()); } catch (IOException ex) { GUILOGGER.error("Error while saving map editor image", ex); } return null; } } /** * This task is created when the user Drag Source from GeoCatalog * to the map directly. The layer is created directly on the root. */ private static class DropDataSourceProcess extends SwingWorkerPM<List<MapElement>, List<MapElement>> { private EditableElement[] editableList; private MapContext mapContext; private EditorManager editorManager; private DropDataSourceProcess(EditableElement[] editableList, MapContext mapContext, EditorManager editorManager) { this.editableList = editableList.clone(); this.mapContext = mapContext; this.editorManager = editorManager; setTaskName(I18N.tr("Load the data source droped into the map editor.")); } @Override protected List<MapElement> doInBackground() throws Exception { List<MapElement> mapElementsToOpen = new ArrayList<>(); ProgressMonitor pm = getProgressMonitor().startTask(editableList.length); ILayer dropLayer = mapContext.getLayerModel(); for (EditableElement eElement : editableList) { if (eElement instanceof EditableSource) { try { EditableSource edit = (EditableSource) eElement; dropLayer.addLayer(mapContext.createLayer(edit.getTableReference())); } catch (LayerException e) { //This layer can not be inserted, we continue to the next layer GUILOGGER.warn(I18N.tr("Unable to create and drop the layer"), e); } } else if (eElement instanceof MapElement) { final MapElement mapElement = (MapElement) eElement; mapElement.open(pm); mapElementsToOpen.add(mapElement); } } return mapElementsToOpen; } @Override protected void done() { try { List<MapElement> mapElements = get(); for (MapElement mapElement : mapElements) { editorManager.openEditable(mapElement); } } catch (InterruptedException | ExecutionException ex) { // Ignore } } } @Override public MapsManagerData getMapsManagerData() { return mapEditorPersistence.getMapsManagerPersistence(); } /** * Compute the cursor projection Coordinate */ private static class CursorCoordinateProcessing extends SwingWorker<Point2D, Point2D> { MapStatusBar mapStatusBar; AtomicBoolean processingCursorPosition; MapTransform mapTransform; Point mousePosition; private CursorCoordinateProcessing(MapStatusBar mapStatusBar, AtomicBoolean processingCursorPosition, MapTransform mapTransform, Point mousePosition) { this.mapStatusBar = mapStatusBar; this.processingCursorPosition = processingCursorPosition; this.mapTransform = mapTransform; this.mousePosition = mousePosition; } @Override public String toString() { return "MapEditor#CursorCoordinateProcessing"; } @Override protected Point2D doInBackground() throws Exception { return mapTransform.toMapPoint(mousePosition.x, mousePosition.y); } @Override protected void done() { super.done(); try { mapStatusBar.setCursorCoordinates(get()); } catch (Exception ex) { GUILOGGER.error(ex.getLocalizedMessage(), ex); } finally { processingCursorPosition.set(false); } } } }