/* Image Georeferencing * * Axios Engineering * http://www.axios.es * * (C) 2011, Axios Engineering S.L. (Axios) * Axios agrees to licence under Lesser General Public License (LGPL). * * You can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software * Foundation; version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package es.axios.udig.georeferencing.internal.ui; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.logging.Logger; import net.refractions.udig.catalog.CatalogPlugin; import net.refractions.udig.catalog.IGeoResource; import net.refractions.udig.catalog.IResolve; import net.refractions.udig.mapgraphic.internal.MapGraphicService; import net.refractions.udig.project.ILayer; import net.refractions.udig.project.IMap; import net.refractions.udig.project.MapCompositionEvent; import net.refractions.udig.project.internal.Layer; import net.refractions.udig.project.internal.commands.DeleteLayerCommand; import net.refractions.udig.project.ui.ApplicationGIS; import net.refractions.udig.project.ui.render.displayAdapter.ViewportPane; import net.refractions.udig.project.ui.tool.IToolContext; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.custom.ViewForm; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; import org.opengis.referencing.crs.CoordinateReferenceSystem; import es.axios.udig.georeferencing.internal.i18n.Messages; import es.axios.udig.georeferencing.internal.preferences.Preferences; import es.axios.udig.georeferencing.internal.process.MarkModel; import es.axios.udig.georeferencing.internal.ui.coordinatepanel.CoordinateTableComposite; import es.axios.udig.georeferencing.internal.ui.coordinatepanel.MapMarksGraphics; import es.axios.udig.georeferencing.internal.ui.imagepanel.ImageComposite; import es.axios.udig.ui.commons.message.InfoMessage; import es.axios.udig.ui.commons.message.InfoMessage.Type; import es.axios.udig.ui.commons.util.MapUtil; /** * Main composite of the georeferencing view. * * @author Mauricio Pazos (www.axios.es) * @author Aritz Davila (www.axios.es) * @since 1.0.0 */ public class MainComposite extends Composite implements Observer, GeoReferencingComposite { @SuppressWarnings("unused") private static final Logger LOGGER = Logger.getLogger(MainComposite.class.getName()); private Composite outputComposite = null; private Composite informationComposite = null; private Composite contentComposite = null; private SashForm sashForm = null; private ImageComposite imageComposite = null; private CoordinateTableComposite coordinateTableComposite = null; private CLabel messageImage = null; private CLabel messageText = null; private IToolContext udigContext = null; private ViewForm viewForm = null; private CLabel outputLabel = null; private Text filePathText = null; private Button browseButton = null; private GeoReferencingCommand cmd = null; private IToolContext toolContext = null; private MapMarksGraphics mapMarkGraphic = null; private ILayer mapGraphicLayer = null; private Thread uiThread = null; /** * This composite will be the responsible to create all the composites. * * @param cmd * The georeferencing command. * @param parent * The parent composite which in this case is the view. * @param style * Style */ public MainComposite(GeoReferencingCommand cmd, Composite parent, int style) { super(parent, style); assert cmd != null; this.cmd = cmd; this.cmd.addObserver(this); createContent(); this.pack(); } private void createContent() { this.uiThread = Thread.currentThread(); viewForm = new ViewForm(this, SWT.NONE); viewForm.setLayout(new FillLayout()); Composite infoComposite = createCompositeLegend(viewForm); viewForm.setTopLeft(infoComposite); contentComposite = new Composite(viewForm, SWT.NONE); contentComposite.setLayout(new GridLayout()); createContentComposite(contentComposite); viewForm.setContent(contentComposite); } private void createContentComposite(Composite parent) { GridData gridData = new GridData(); gridData.horizontalAlignment = GridData.FILL; gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = true; gridData.verticalAlignment = GridData.FILL; GridData gridData2 = new GridData(); gridData2.horizontalAlignment = GridData.FILL; gridData2.grabExcessHorizontalSpace = true; gridData2.grabExcessVerticalSpace = false; gridData2.verticalAlignment = GridData.FILL; sashForm = new SashForm(parent, SWT.V_SCROLL); sashForm.setOrientation(SWT.HORIZONTAL); sashForm.setLayout(new GridLayout()); sashForm.setLayoutData(gridData); createImageComposite(sashForm); createCoordinateTableComposite(sashForm); GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 3; outputComposite = new Composite(parent, SWT.BORDER); outputComposite.setLayout(gridLayout); outputComposite.setLayoutData(gridData2); createOutputBrowser(outputComposite); } private void createOutputBrowser(Composite parent) { GridData gridData = new GridData(); gridData.horizontalAlignment = GridData.BEGINNING; gridData.grabExcessHorizontalSpace = false; gridData.grabExcessVerticalSpace = false; gridData.verticalAlignment = GridData.FILL; GridData gridData2 = new GridData(); gridData2.horizontalAlignment = GridData.FILL; gridData2.grabExcessHorizontalSpace = true; gridData2.grabExcessVerticalSpace = false; gridData2.verticalAlignment = GridData.END; outputLabel = new CLabel(parent, SWT.NONE); outputLabel.setText(Messages.MainComposite_outputText); outputLabel.setToolTipText(Messages.MainComposite_outputToolTip); outputLabel.setLayoutData(gridData); filePathText = new Text(parent, SWT.BORDER); filePathText.setLayoutData(gridData2); filePathText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent me) { cmd.setOutputFileName(filePathText.getText()); cmd.evalPrecondition(); } }); browseButton = new Button(parent, SWT.NONE); browseButton.setText(Messages.MainComposite_browseText); browseButton.addMouseListener(new MouseAdapter() { @Override public void mouseUp(MouseEvent e) { Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); FileDialog fd = new FileDialog(shell, SWT.SAVE); fd.setFilterExtensions(new String[] { "*.tif" }); //$NON-NLS-1$ fd.setText("Save file"); //$NON-NLS-1$ fd.setFilterPath(Preferences.getOutputFilePath()); // fd.setFilterPath(cmd.getOutputFilePath()); String filename = fd.open(); if (filename != null) { filePathText.setText(filename); cmd.setOutputFileName(filename); cmd.evalPrecondition(); // store the path to load in further attempts File file = new File(filename); Preferences.setOutputFilePath(file.getParent()); // cmd.setOutputFilePath(file.getParent()); } } }); } private Composite createCompositeLegend(final Composite parent) { GridLayout layout = new GridLayout(); layout.numColumns = 1; GridData gridData = new GridData(); gridData.horizontalAlignment = GridData.FILL; gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = false; gridData.minimumHeight = 300; gridData.minimumWidth = 500; gridData.verticalAlignment = SWT.CENTER; Composite compositeSelection = new Composite(parent, SWT.BORDER); compositeSelection.setLayoutData(gridData); compositeSelection.setLayout(layout); createCompositeInformation(compositeSelection); return compositeSelection; } /** * This method initializes compositeInformation * */ private void createCompositeInformation(final Composite parent) { GridData gridData6 = new GridData(); gridData6.horizontalAlignment = GridData.FILL; gridData6.grabExcessHorizontalSpace = true; gridData6.grabExcessVerticalSpace = true; gridData6.verticalAlignment = GridData.FILL; informationComposite = new Composite(parent, SWT.NONE); GridLayout gridLayout = new GridLayout(3, false); informationComposite.setLayoutData(gridData6); informationComposite.setLayout(gridLayout); this.messageImage = new CLabel(informationComposite, SWT.NONE); GridData gridData7 = new GridData(); gridData7.horizontalAlignment = GridData.BEGINNING; gridData7.minimumWidth = 30; gridData7.widthHint = 30; this.messageImage.setLayoutData(gridData7); this.messageText = new CLabel(informationComposite, SWT.NONE); GridData gridData8 = new GridData(); gridData8.horizontalAlignment = GridData.FILL; gridData8.grabExcessHorizontalSpace = true; gridData8.grabExcessVerticalSpace = true; gridData8.verticalAlignment = GridData.FILL; this.messageText.setLayoutData(gridData8); this.messageText.setFont(JFaceResources.getDialogFont()); InfoMessage message = this.cmd.getMessage(); displayMessage(message); } private void createImageComposite(Composite parent) { this.imageComposite = new ImageComposite(this.cmd, parent, SWT.BORDER | SWT.NO_FOCUS); this.cmd.addObserver(this.imageComposite); } private void createCoordinateTableComposite(Composite parent) { ScrolledComposite scrollComposite = new ScrolledComposite(parent, SWT.NONE | SWT.H_SCROLL | SWT.V_SCROLL); scrollComposite.setLayout(new FillLayout()); this.coordinateTableComposite = new CoordinateTableComposite(this.cmd, scrollComposite, SWT.NONE | SWT.NO_FOCUS); this.coordinateTableComposite.setLayout(new FillLayout()); this.cmd.addObserver(coordinateTableComposite); // adds the parameters container to scroll composite scrollComposite.setContent(coordinateTableComposite); scrollComposite.setExpandHorizontal(true); scrollComposite.setExpandVertical(true); scrollComposite.setMinHeight(300); } /** * Shows the message in the standard information area */ private void displayMessage(final InfoMessage message) { assert message != null; // The following sentences does a filter of those obvious messages InfoMessage filteredMessage = message; // shows the message this.informationComposite.setVisible(true); this.messageImage.setImage(filteredMessage.getImage()); this.messageText.setToolTipText(filteredMessage.getText()); this.messageText.setText(filteredMessage.getText()); } /** * Executes the operation associated to selected control. * */ public void executeOperation() { setEnabled(false); // sets the wait cursor and disables this panel ViewportPane pane = this.udigContext.getViewportPane(); Display display = getDisplay(); pane.setCursor(display.getSystemCursor(SWT.CURSOR_WAIT)); this.cmd.execute(); pane.setCursor(null); setEnabled(true); } public void update(Observable o, Object arg) { InfoMessage message = this.cmd.getMessage(); // listen to the map change notification so it can broadcast the set // enable=false to all his children's. if (!(arg instanceof GeoreferencingCommandEventChange)) return; GeoreferencingCommandEventChange cmdEvent = (GeoreferencingCommandEventChange) arg; switch (cmdEvent.getEvent()) { case MAP_CHANGE: message.setType(Type.WARNING); setEnabled(false); break; case MAP_CHANGE_TO_ORIGINAL: message.setType(Type.INFORMATION); setEnabled(true); default: break; } displayMessage(message); } public void setContext(IToolContext context) { IMap map; if (context != null) { map = context.getMap(); CoordinateReferenceSystem crs = getCurrentMapCrs(map); // create the mapGraphics try { createTheMapGraphic(map); } catch (IOException e) { InfoMessage info = new InfoMessage(Messages.MainComposite_mapGraphicFailText, Type.FAIL); setMessage(info); e.printStackTrace(); } // set the values on the command. this.cmd.setCRS(crs); this.cmd.setMap(map); this.cmd.evalPrecondition(); } if (this.toolContext == null) { this.toolContext = context; // add the listeners the first time this.mapMarkGraphic.associateListeners(this.coordinateTableComposite, this.imageComposite); } ((GeoReferencingComposite) imageComposite).setContext(context); ((GeoReferencingComposite) coordinateTableComposite).setContext(context); } /** * @param map * @return the current map's CRS or null if current map is null */ private CoordinateReferenceSystem getCurrentMapCrs(IMap map) { CoordinateReferenceSystem crs = (map != null) ? MapUtil.getCRS(map) : null; return crs; } public void setMessage(InfoMessage info) { displayMessage(info); } /** * Delete the {@link MapMarksGraphics} and the listeners associated with it. */ public void close() { imageComposite.close(this); coordinateTableComposite.close(this); // remove the mapGraphic try { if (mapMarkGraphic != null) { mapMarkGraphic.deleteAssociatedListeners(this.coordinateTableComposite, this.imageComposite); getMapMarkGraphic().clear(); IMap map = cmd.getMap(); removeOldMapGraphicFromLayer(map); } } catch (IOException e) { // we are closing the view, there is no need to inform the user // about this exception. e.printStackTrace(); } finally { mapMarkGraphic = null; } } @Override public void setEnabled(boolean enabled) { imageComposite.setEnabled(enabled); coordinateTableComposite.setEnabled(enabled); informationComposite.setEnabled(enabled); super.setEnabled(enabled); } /** * Given the loaded marks, create the marks and create the associated * presenters for each one of them. * * After creating all of them, refresh it so the established data can be * seen. * * @param marks */ public void createMarks(Map<String, MarkModel> marks) { imageComposite.createMarks(marks); refreshMapGraphicLayer(); setCursor(null); } /** * Communicates with the imageComposite and tell him to delete all the marks * from the image. */ public void deleteAllPoints() { setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_WAIT)); imageComposite.deleteAllPoints(); } /** * If the toolContext isn't null and the mapMarkGraphic wasn't created yet, * create it now. * * @param map2 * * @throws IOException * @throws InterruptedException */ private void createTheMapGraphic(IMap map) throws IOException { if (getMapMarkGraphic() != null) { return; } removeOldMapGraphicFromLayer(map); List<IResolve> mapgraphics = CatalogPlugin.getDefault().getLocalCatalog() .find(MapGraphicService.SERVICE_URL, null); List<IResolve> members = new ArrayList<IResolve>(); members = mapgraphics.get(0).members(null); assert members != null; IGeoResource resolved = null; for (IResolve resolve : members) { if (resolve.canResolve(MapMarksGraphics.class)) { resolved = resolve.resolve(IGeoResource.class, null); break; } } assert resolved != null; ApplicationGIS.addLayersToMap(map, Collections.singletonList(resolved), -1); // Get the newly added mapgraphic layer, add the current images to // it, // and store it List<ILayer> mapLayers = map.getMapLayers(); Iterator<ILayer> iterator = mapLayers.iterator(); while (iterator.hasNext()) { ILayer layer = iterator.next(); IGeoResource geoResource = layer.findGeoResource(MapMarksGraphics.class); if (geoResource != null) { MapMarksGraphics mapGraphic = geoResource.resolve(MapMarksGraphics.class, null); this.mapMarkGraphic = mapGraphic; this.mapGraphicLayer = layer; break; } } assert getMapMarkGraphic() != null; } /** * Removes the old mapGraphic layer from the layer list. * * @param map * @throws IOException */ private void removeOldMapGraphicFromLayer(IMap map) throws IOException { // remove the mapgraphic layer from the map List<ILayer> mapLayers = map.getMapLayers(); Iterator<ILayer> iterator = mapLayers.iterator(); while (iterator.hasNext()) { ILayer layer = iterator.next(); IGeoResource geoResource = layer.findGeoResource(MapMarksGraphics.class); if (geoResource != null) { map.sendCommandASync(new DeleteLayerCommand((Layer) layer)); break; } } } public MapMarksGraphics getMapMarkGraphic() { return this.mapMarkGraphic; } public ILayer getMapGraphicLayer() { return this.mapGraphicLayer; } public void refreshMapGraphicLayer() { mapGraphicLayer.refresh(null); } /** * This method is called if the collection of layer is updated (added or * removed). * * // TODO work in progress. * * @param event */ private void updatedMapLayersActions(final MapCompositionEvent event) { MapCompositionEvent.EventType eventType = event.getType(); switch (eventType) { case ADDED: case MANY_ADDED: Display.findDisplay(uiThread).asyncExec(new Runnable() { public void run() { } }); break; default: break; } } /** * Adds a {@link MouseSelectionListener} to the {@link ImageComposite}. * * @param listener * The listener. */ public void addMouseSelectionListenerToImgComposite(MouseSelectionListener listener) { this.imageComposite.addMouseSelectionListener(listener); } /** * Deletes a {@link MouseSelectionListener} on the {@link ImageComposite}. * * @param listener * The listener. */ public void deleteMouseSelectionListenerToImgComposite(MouseSelectionListener listener) { this.imageComposite.deleteMouseSelectionListener(listener); } /** * Adds a {@link MouseSelectionListener} to the * {@link CoordinateTableComposite}. * * @param listener * The listener. */ public void addMouseSelectionListenerToCoordinate(MouseSelectionListener listener) { this.coordinateTableComposite.addMouseSelectionListener(listener); } /** * Deletes a {@link MouseSelectionListener} to the * {@link CoordinateTableComposite}. * * @param listener * The listener. */ public void deleteMouseSelectionListenerToCoordinate(MouseSelectionListener listener) { this.coordinateTableComposite.deleteMouseSelectionListener(listener); } }