es.axios.udig.georeferencing.internal.ui.coordinatepanel.CoordinateTableComposite.java Source code

Java tutorial

Introduction

Here is the source code for es.axios.udig.georeferencing.internal.ui.coordinatepanel.CoordinateTableComposite.java

Source

/* 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.coordinatepanel;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;

import net.refractions.udig.project.IMap;
import net.refractions.udig.project.ui.ApplicationGIS;
import net.refractions.udig.project.ui.tool.IToolContext;
import net.refractions.udig.project.ui.tool.Tool;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import com.vividsolutions.jts.geom.Coordinate;

import es.axios.udig.georeferencing.internal.i18n.Messages;
import es.axios.udig.georeferencing.internal.process.MarkModel;
import es.axios.udig.georeferencing.internal.process.MarkModel.MarkModelChange;
import es.axios.udig.georeferencing.internal.ui.GeoReferencingCommand;
import es.axios.udig.georeferencing.internal.ui.GeoReferencingComposite;
import es.axios.udig.georeferencing.internal.ui.GeoreferencingCommandEventChange;
import es.axios.udig.georeferencing.internal.ui.InputEvent;
import es.axios.udig.georeferencing.internal.ui.MainComposite;
import es.axios.udig.georeferencing.internal.ui.MouseSelectionListener;
import es.axios.udig.georeferencing.internal.ui.coordinatepanel.tools.AddCoordinateTool;
import es.axios.udig.georeferencing.internal.ui.coordinatepanel.tools.CapturedCoordinateListener;
import es.axios.udig.georeferencing.internal.ui.coordinatepanel.tools.DeleteCoordinateTool;
import es.axios.udig.georeferencing.internal.ui.coordinatepanel.tools.DeletedCoordinateListener;
import es.axios.udig.georeferencing.internal.ui.coordinatepanel.tools.MoveCoordinateListener;
import es.axios.udig.georeferencing.internal.ui.coordinatepanel.tools.MoveCoordinateTool;
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;

/**
 * Composite responsible of managing the mark model coordinates edit operations
 * with the aid of tools that interact with the map and a table to directly edit
 * them.
 * 
 * It's also an observer of the {@link GeoReferencingCommand} and
 * {@link MarkModel}.
 * 
 * @author Mauricio Pazos (www.axios.es)
 * @author Aritz Davila (www.axios.es)
 * @since 1.0.0
 * 
 */
public final class CoordinateTableComposite extends Composite implements Observer, GeoReferencingComposite {

    private CLabel crsLabel = null;
    private CLabel mapLabel;
    private Table coordinatesTable = null;

    private Composite compositeGridCoord = null;
    private GeoReferencingCommand cmd = null;
    private IToolContext toolContext = null;

    private TableColumn tableColumnX = null;
    private TableColumn tableColumnY = null;
    private TableColumn tableColumnID = null;
    private TableEditor editorX = null;
    private TableEditor editorY = null;

    @SuppressWarnings("unused")
    private Thread uiThread = null;

    private CapturedCoordinateListener capturedListener = null;
    private DeletedCoordinateListener deletedListener = null;
    private MoveCoordinateListener moveListener = null;

    private MouseSelectionListener mapSelectionListener = null;
    private MouseSelectionListener imageSelectionListener = null;

    private AddCoordinateTool coordTool = null;
    private DeleteCoordinateTool deleteTool = null;
    private MoveCoordinateTool moveTool = null;

    private ToolBar mapToolBar = null;
    private ToolItem itemAdd = null;
    private ToolItem itemDelete = null;
    private ToolItem itemMove = null;
    private ImageRegistry registry = null;

    private List<MouseSelectionListener> listeners = new LinkedList<MouseSelectionListener>();
    private ToolItem itemDeleteAll;

    /**
     * Constructor method.
     * 
     * @param cmd
     *            The georeferencing command.
     * @param parent
     *            The parent composite.
     * @param style
     *            The style.
     */
    public CoordinateTableComposite(GeoReferencingCommand cmd, Composite parent, int style) {

        super(parent, style);

        assert cmd != null;
        this.cmd = cmd;
        createContent();
    }

    private void createContent() {

        this.registry = createImageRegistry();
        this.uiThread = Thread.currentThread();

        createListeners();
        getTools();

        GridLayout gridLayout2 = new GridLayout();
        gridLayout2.numColumns = 2;
        gridLayout2.makeColumnsEqualWidth = true;

        compositeGridCoord = new Composite(this, SWT.BORDER);
        compositeGridCoord.setLayout(gridLayout2);

        createCRSselector(compositeGridCoord);
        createToolbar(compositeGridCoord);
        createGrid(compositeGridCoord);
    }

    /**
     * Creates the required listeners, the majority of them are tool listeners.
     */
    private void createListeners() {

        this.capturedListener = new CapturedCoordinateListener() {

            public void capturedCoordinate(Coordinate newCoord) {

                addCoordinateFromMapToTable(newCoord);

                assert getMainComposite().getMapMarkGraphic() != null;
                getMainComposite().refreshMapGraphicLayer();
            }

            public void activated(boolean active) {

                itemAdd.setSelection(active);
            }
        };

        this.deletedListener = new DeletedCoordinateListener() {

            public void deletedCoordinate(java.awt.Point point, InputEvent event) {

                deleteFromTable(point, event);

                // feedback to show the removed coordinate
                assert getMainComposite().getMapMarkGraphic() != null;
                getMainComposite().refreshMapGraphicLayer();
            }

            public void activated(boolean active) {

                itemDelete.setSelection(active);
            }

        };

        this.moveListener = new MoveCoordinateListener() {

            public void MoveCoordinate(java.awt.Point coor, InputEvent event) {

                moveFromTable(coor, event);

                // feedback to show the removed coordinate
                assert getMainComposite().getMapMarkGraphic() != null;
                getMainComposite().refreshMapGraphicLayer();
            }

            public void activated(boolean active) {

                itemMove.setSelection(active);

            }
        };

        this.mapSelectionListener = new MouseSelectionListener() {

            public void inEvent(MarkModel mark) {

                selectRow(mark);
            }

            public void outEvent(MarkModel mark) {

                deselectRow(mark);
            }
        };

        this.imageSelectionListener = new MouseSelectionListener() {

            public void inEvent(MarkModel mark) {

                selectRow(mark);
            }

            public void outEvent(MarkModel mark) {

                deselectRow(mark);
            }
        };
    }

    /**
     * Creates the {@link ImageRegistry} that stores the image shown by the
     * tools.
     * 
     * @return The imageRegistry.
     */
    private ImageRegistry createImageRegistry() {

        ImageRegistry registry = new ImageRegistry(this.getDisplay());

        String opId = "Delete"; //$NON-NLS-1$
        String imgFile = "image/delete.gif"; //$NON-NLS-1$ 
        registry.put(opId, ImageDescriptor.createFromFile(CoordinateTableComposite.class, imgFile));

        opId = "Add"; //$NON-NLS-1$
        imgFile = "image/add.png"; //$NON-NLS-1$ 
        registry.put(opId, ImageDescriptor.createFromFile(CoordinateTableComposite.class, imgFile));

        opId = "Move"; //$NON-NLS-1$
        imgFile = "image/movemarker.png"; //$NON-NLS-1$ 
        registry.put(opId, ImageDescriptor.createFromFile(CoordinateTableComposite.class, imgFile));

        opId = "DeleteAll"; //$NON-NLS-1$
        imgFile = "image/deleteAll.gif"; //$NON-NLS-1$ 
        registry.put(opId, ImageDescriptor.createFromFile(CoordinateTableComposite.class, imgFile));

        return registry;
    }

    /**
     * Gets a reference to the tools and add the listeners.
     */
    private void getTools() {

        Tool tool = ApplicationGIS.getToolManager().findTool(AddCoordinateTool.ID);
        this.coordTool = (AddCoordinateTool) tool;
        this.coordTool.addCapturedCoordinateListener(capturedListener);

        tool = ApplicationGIS.getToolManager().findTool(DeleteCoordinateTool.ID);
        this.deleteTool = (DeleteCoordinateTool) tool;
        this.deleteTool.addDeletedCoordinateListener(deletedListener);

        tool = ApplicationGIS.getToolManager().findTool(MoveCoordinateTool.ID);
        this.moveTool = (MoveCoordinateTool) tool;
        this.moveTool.addMoveCoordinateListener(moveListener);
    }

    private void createCRSselector(Composite parent) {

        GridData gridData = new GridData();
        gridData.horizontalAlignment = GridData.FILL;
        gridData.grabExcessHorizontalSpace = true;
        gridData.grabExcessVerticalSpace = false;
        gridData.horizontalSpan = 1;
        gridData.verticalAlignment = GridData.FILL;

        mapLabel = new CLabel(parent, SWT.NONE);
        mapLabel.setText(Messages.CoordinateTableComposite_map);
        mapLabel.setLayoutData(gridData);

        crsLabel = new CLabel(parent, SWT.NONE);
        crsLabel.setText("CRS:"); //$NON-NLS-1$
        crsLabel.setLayoutData(gridData);
    }

    /**
     * Creates the toolbar that contains the tools that interact with the map.
     * 
     * @param parent
     *            The parent composite.
     */
    private void createToolbar(Composite parent) {

        GridData gridData = new GridData();
        gridData.horizontalAlignment = GridData.FILL;
        gridData.grabExcessHorizontalSpace = true;
        gridData.grabExcessVerticalSpace = false;
        gridData.horizontalSpan = 2;
        gridData.verticalAlignment = GridData.FILL;

        mapToolBar = new ToolBar(parent, SWT.LEFT_TO_RIGHT);

        final IAction addTool = ApplicationGIS.getToolManager().getToolAction(AddCoordinateTool.ID,
                AddCoordinateTool.CATEGORY_ID);

        itemAdd = new ToolItem(mapToolBar, SWT.RADIO);
        itemAdd.setImage(this.registry.get("Add")); //$NON-NLS-1$
        itemAdd.setToolTipText(Messages.CoordinateTableComposite_itemAddTooltip);
        itemAdd.addListener(SWT.Selection, new Listener() {

            public void handleEvent(Event event) {

                addTool.run();
            }
        });

        final IAction deleteTool = ApplicationGIS.getToolManager().getToolAction(DeleteCoordinateTool.ID,
                DeleteCoordinateTool.CATEGORY_ID);

        itemDelete = new ToolItem(mapToolBar, SWT.RADIO);
        itemDelete.setImage(this.registry.get("Delete")); //$NON-NLS-1$
        itemDelete.setToolTipText(Messages.CoordinateTableComposite_itemDeleteTooltip);
        itemDelete.addListener(SWT.Selection, new Listener() {

            public void handleEvent(Event event) {

                deleteTool.run();
            }
        });

        final IAction moveTool = ApplicationGIS.getToolManager().getToolAction(MoveCoordinateTool.ID,
                MoveCoordinateTool.CATEGORY_ID);

        itemMove = new ToolItem(mapToolBar, SWT.RADIO);
        itemMove.setImage(this.registry.get("Move")); //$NON-NLS-1$
        itemMove.setToolTipText(Messages.CoordinateTableComposite_itemMoveTooltip);
        itemMove.addListener(SWT.Selection, new Listener() {

            public void handleEvent(Event event) {

                moveTool.run();
            }
        });

        itemDeleteAll = new ToolItem(mapToolBar, SWT.PUSH);
        itemDeleteAll.setImage(this.registry.get("DeleteAll")); //$NON-NLS-1$
        itemDeleteAll.setToolTipText(Messages.CoordinateTableComposite_itemDeleteAll_Tooltip);
        itemDeleteAll.addListener(SWT.Selection, new Listener() {

            public void handleEvent(Event event) {

                deleteAllGCP();
            }
        });

        setItemsEnabled(false);
        setCertainItemsEnabled(false);
    }

    private void setItemsEnabled(boolean enabled) {

        itemAdd.setEnabled(enabled);
    }

    private void setCertainItemsEnabled(boolean enabled) {

        itemDelete.setEnabled(enabled);
        itemMove.setEnabled(enabled);
        itemDeleteAll.setEnabled(enabled);

        if (!enabled) {
            itemDelete.setSelection(false);
            itemMove.setSelection(false);
            itemDeleteAll.setSelection(false);
        }
    }

    private void createGrid(final Composite parent) {

        GridData gridData = new GridData();
        gridData.horizontalAlignment = GridData.FILL;
        gridData.grabExcessHorizontalSpace = true;
        gridData.grabExcessVerticalSpace = true;
        gridData.horizontalSpan = 2;
        gridData.verticalAlignment = GridData.FILL;

        coordinatesTable = new Table(parent,
                SWT.BORDER | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.HIDE_SELECTION);
        coordinatesTable.setHeaderVisible(true);
        coordinatesTable.setLayoutData(gridData);
        coordinatesTable.setLinesVisible(true);

        tableColumnID = new TableColumn(coordinatesTable, SWT.NONE);
        tableColumnID.setWidth(45);
        tableColumnID.setText("ID"); //$NON-NLS-1$
        tableColumnID.setMoveable(true);
        tableColumnID.setResizable(true);

        tableColumnX = new TableColumn(coordinatesTable, SWT.NONE);
        tableColumnX.setText("X"); //$NON-NLS-1$
        tableColumnX.setMoveable(true);
        tableColumnX.setResizable(true);

        tableColumnY = new TableColumn(coordinatesTable, SWT.NONE);
        tableColumnY.setText("Y"); //$NON-NLS-1$
        tableColumnY.setMoveable(true);
        tableColumnY.setResizable(true);

        parent.addControlListener(new ControlAdapter() {
            @Override
            public void controlResized(ControlEvent e) {
                Rectangle area = parent.getClientArea();
                Point size = coordinatesTable.computeSize(SWT.DEFAULT, SWT.DEFAULT);
                ScrollBar vBar = coordinatesTable.getVerticalBar();
                int width = area.width - coordinatesTable.computeTrim(0, 0, 0, 0).width - vBar.getSize().x;
                if (size.y > area.height + coordinatesTable.getHeaderHeight()) {
                    // Subtract the scrollbar width from the total column width
                    // if a vertical scrollbar will be required
                    Point vBarSize = vBar.getSize();
                    width -= vBarSize.x;
                }
                Point oldSize = coordinatesTable.getSize();
                if (oldSize.x > area.width) {
                    // table is getting smaller so make the columns
                    // smaller first and then resize the table to
                    // match the client area width
                    tableColumnX.setWidth(width / 3);
                    tableColumnY.setWidth(width - tableColumnX.getWidth());
                    coordinatesTable.setSize(area.width, area.height);
                } else {
                    // table is getting bigger so make the table
                    // bigger first and then make the columns wider
                    // to match the client area width
                    coordinatesTable.setSize(area.width, area.height);
                    tableColumnX.setWidth(width / 3);
                    tableColumnY.setWidth(width - tableColumnX.getWidth());
                }
            }
        });

        editorX = new TableEditor(coordinatesTable);
        // The editor must have the same size as the cell and must
        // not be any smaller than 50 pixels.
        editorX.horizontalAlignment = SWT.LEFT;
        editorX.grabHorizontal = true;
        editorX.minimumWidth = 50;

        editorY = new TableEditor(coordinatesTable);
        // The editor must have the same size as the cell and must
        // not be any smaller than 50 pixels.
        editorY.horizontalAlignment = SWT.LEFT;
        editorY.grabHorizontal = true;
        editorY.minimumWidth = 50;

        coordinatesTable.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                // Clean up any previous editor control
                deleteOldEditors();

                // Identify the selected row
                final TableItem item = (TableItem) e.item;
                if (item == null)
                    return;
                // get the mark associated to this row.
                final MarkModel mark = (MarkModel) item.getData();

                createEditorColumnX(mark, item);

                createEditorColumnY(mark, item);
                // show feedback using listeners
                broadcastSelectionInEvent(mark);

                getMainComposite().refreshMapGraphicLayer();
            }
        });
    }

    /**
     * Creates the column editor to edit the X coordinate values.
     * 
     * @param mark
     *            Associated mark model
     * @param item
     *            Table item.
     */
    private void createEditorColumnX(final MarkModel mark, final TableItem item) {

        // The control that will be the editor must be a child of the
        // Table
        final Text editorColumnX = new Text(coordinatesTable, SWT.NONE);
        if (mark != null && !(mark.getXCoord().equals(Double.NaN))) {

            editorColumnX.setText(String.valueOf(mark.getXCoord()));
        }
        editorColumnX.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {

                Text text = (Text) editorX.getEditor();
                String newText = text.getText();
                if (mark != null) {
                    try {
                        // first, try to parse the text into double
                        Double value = Double.parseDouble(newText);
                        mark.setXCoord(value);
                        cmd.evalPrecondition();
                        getMainComposite().refreshMapGraphicLayer();
                    } catch (NumberFormatException ex) {
                        if (newText.equals("")) { //$NON-NLS-1$
                            mark.setXCoord(Double.NaN);
                        } else {
                            newText = String.valueOf(mark.getXCoord());
                        }
                        cmd.evalPrecondition();
                        getMainComposite().refreshMapGraphicLayer();
                    }
                }
                item.setText(1, newText);
            }
        });
        editorColumnX.addKeyListener(new KeyListener() {

            public void keyReleased(KeyEvent e) {
                // not used
            }

            public void keyPressed(KeyEvent e) {

                try {
                    validateCharacter(e);
                } catch (NumberFormatException ex) {
                    e.doit = false;
                }
            }
        });
        editorColumnX.selectAll();
        editorColumnX.setFocus();
        editorX.setEditor(editorColumnX, item, 1);
    }

    /**
     * Creates the column editor to edit the Y coordinate values.
     * 
     * @param mark
     *            Associated mark model
     * @param item
     *            Table item.
     */
    private void createEditorColumnY(final MarkModel mark, final TableItem item) {

        final Text editorColumnY = new Text(coordinatesTable, SWT.NONE);
        if (mark != null && !(mark.getYCoord().equals(Double.NaN))) {
            editorColumnY.setText(String.valueOf(mark.getYCoord()));
        }
        editorColumnY.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {

                Text text = (Text) editorY.getEditor();
                String newText = text.getText();
                if (mark != null) {
                    try {
                        // first, try to parse the text into double
                        Double value = Double.parseDouble(newText);
                        mark.setYCoord(value);
                        cmd.evalPrecondition();
                        getMainComposite().refreshMapGraphicLayer();
                    } catch (NumberFormatException ex) {
                        if (newText.equals("")) { //$NON-NLS-1$
                            mark.setYCoord(Double.NaN);
                        } else {
                            newText = String.valueOf(mark.getYCoord());
                        }
                        cmd.evalPrecondition();
                        getMainComposite().refreshMapGraphicLayer();
                    }
                }
                item.setText(2, newText);
            }
        });
        editorColumnY.addKeyListener(new KeyListener() {

            public void keyReleased(KeyEvent e) {
                // not used
            }

            public void keyPressed(KeyEvent e) {

                try {
                    validateCharacter(e);
                } catch (NumberFormatException ex) {
                    e.doit = false;
                }
            }
        });
        editorY.setEditor(editorColumnY, item, 2);
    }

    /**
     * Delete old editors from the coordinate table.
     */
    private void deleteOldEditors() {

        Control oldEditorX = editorX.getEditor();
        if (oldEditorX != null)
            oldEditorX.dispose();

        Control oldEditorY = editorY.getEditor();
        if (oldEditorY != null)
            oldEditorY.dispose();
    }

    /**
     * Listen to the changes occurred to the command and to the mark model.
     */
    public void update(Observable obs, Object arg) {

        if (obs instanceof GeoReferencingCommand) {

            setCertainItemsEnabled(cmd.canEnableMapTools());

            GeoreferencingCommandEventChange cmdEvent = (GeoreferencingCommandEventChange) arg;
            MarkModel mark = cmdEvent.getMark();

            switch (cmdEvent.getEvent()) {
            case MARK_ADDED:
                addMarkOnTable(mark);
                break;
            case MARK_DELETED:
                deleteMarkOnTable(mark);
                break;
            case ALL_MARKS_DELETED:
                deleteAllMarksOnTable();
                break;
            default:
                break;
            }

        } else if (obs instanceof MarkModel) {

            MarkModel mark = (MarkModel) obs;
            MarkModelChange event = (MarkModelChange) arg;
            switch (event) {
            case MODIFY:
                modifyCoordinateOnTable(mark);
                break;

            default:
                break;
            }
        }

    }

    /**
     * Find the row that contains a reference to this mark model and update the
     * values of that row.
     * 
     * @param mark
     *            The mark model.
     */
    private void modifyCoordinateOnTable(MarkModel mark) {

        boolean selection = false;
        TableItem[] selectedItems = coordinatesTable.getSelection();
        if (selectedItems.length > 0) {
            selection = true;
        }
        // find the row.
        TableItem[] items = coordinatesTable.getItems();
        for (TableItem item : items) {

            MarkModel compareMark = (MarkModel) item.getData();
            if (mark.equals(compareMark)) {

                Coordinate newCoord = new Coordinate(mark.getXCoord(), mark.getYCoord());
                if (selection && selectedItems[0].equals(item)) {
                    // the selected item is the one to update
                    createEditorsAndSetText(mark, item, newCoord);
                }

                setRowData(item, mark, newCoord);
            }
        }

    }

    /**
     * Creates the table editors and set the current value.
     * 
     * @param mark
     *            MarkModel model.
     * @param item
     *            Table item.
     * @param newCoord
     *            Coordinate with the values.
     */
    private void createEditorsAndSetText(MarkModel mark, TableItem item, Coordinate newCoord) {

        deleteOldEditors();
        createEditorColumnX(mark, item);
        createEditorColumnY(mark, item);

        Text textX = (Text) editorX.getEditor();
        Text textY = (Text) editorY.getEditor();
        if (!(Double.isNaN(newCoord.x))) {
            textX.setText(String.valueOf(newCoord.x));
        }
        if (!(Double.isNaN(newCoord.y))) {
            textY.setText(String.valueOf(newCoord.y));
        }

    }

    /**
     * <p>
     * Adds a mark to the table.
     * 
     * Creates a {@link MarkMapPresenterImp} and associates it with the
     * {@link MapMarksGraphics}.
     * </p>
     * 
     * @param mark
     *            Mark model.
     */
    private void addMarkOnTable(MarkModel mark) {

        final TableItem tableItem = new TableItem(coordinatesTable, SWT.NONE);

        // set the mark data to this entire row.
        tableItem.setData(mark);
        tableItem.setText(0, String.valueOf(mark.getID()));

        if (!mark.getXCoord().equals(Double.NaN)) {
            tableItem.setText(1, String.valueOf(mark.getXCoord()));
        }
        if (!mark.getYCoord().equals(Double.NaN)) {
            tableItem.setText(2, String.valueOf(mark.getYCoord()));
        }

        // if a previous row is selected, select the new created row.
        updateRowSelection(tableItem, mark);

        assert getMainComposite().getMapMarkGraphic() != null;

        // create the MarkMapGraphics associated to this mark
        MarkMapPresenter markPresenter = new MarkMapPresenterImp(mark);
        getMainComposite().getMapMarkGraphic().addMarkMapPresenter(markPresenter);

        setItemsEnabled(true);

        mark.addObserver(this);
    }

    /**
     * Given the next scenario:
     * 
     * <pre>
     * - New row added 
     * - There was a previous row selected.
     * </pre>
     * 
     * Update the selected row so it'll select the newly created row.
     * 
     * @param tableItem
     *            Table item.
     * @param mark
     *            Mark model.
     */
    private void updateRowSelection(TableItem addedItem, MarkModel mark) {

        TableItem[] selection = coordinatesTable.getSelection();

        if (selection.length > 0) {

            // get the new item
            coordinatesTable.setSelection(addedItem);

            deleteOldEditors();

            createEditorColumnX(mark, addedItem);
            createEditorColumnY(mark, addedItem);
        }
    }

    /**
     * Adds a coordinate to the table.
     * 
     * There must be 1 empty row. If there is a selected row and also is empty,
     * then the coordinate will be added there. If there isn't any selected row,
     * the coordinate will be added in the first empty row. If there isn't any
     * empty rows, the coordinate won't be added.
     * 
     * 
     * @param newCoord
     *            Coordinate to be added.
     */
    private void addCoordinateFromMapToTable(Coordinate newCoord) {

        TableItem[] selection = coordinatesTable.getSelection();

        if (selection.length > 0) {
            // selected item
            // get the row and add the coordinate to that row.
            TableItem item = selection[0];
            addCoordinateOnTable(item, newCoord, true);
        } else {// non selected item
            // get the first empty row and add the coordinate to that row.
            boolean added = false;
            TableItem[] items = coordinatesTable.getItems();
            for (TableItem item : items) {

                added = addCoordinateOnTable(item, newCoord, false);
                // if the coordinate was added, return.
                if (added)
                    return;
            }
            // if the code reach this point, the coordinate wasn't added, show
            // an advertise message.
            getMainComposite()
                    .setMessage(new InfoMessage(Messages.CoordinateTableComposite_cant_add_gcp, Type.WARNING));
        }
    }

    /**
     * Finds the {@link MainComposite} and returns it.
     * 
     * @return The main composite.
     */
    private MainComposite getMainComposite() {

        if (isDisposed()) {
            return null;
        }
        Composite parent = getParent();
        for (;;) {
            if (parent instanceof MainComposite) {
                return (MainComposite) parent;
            } else {
                parent = parent.getParent();
            }
        }
    }

    /**
     * Validate if the given character is a valid integer.
     * 
     * @param e
     * @throws NumberFormatException
     *             When the given character isn't an Integer.
     */
    private void validateCharacter(KeyEvent e) throws NumberFormatException {

        if (e.character == '.' || e.keyCode == SWT.DEL || e.keyCode == SWT.BS || e.keyCode == SWT.END
                || e.keyCode == SWT.HOME || e.keyCode == 16777219 || e.keyCode == 16777220 || e.character == '-'
                || e.character == '+') {
            return;
        }

        Integer.parseInt(String.valueOf(e.character));
    }

    /**
     * Delete this mark on the table and refresh the layer that contains the
     * mapGraphic so the changed are shown.
     * 
     * @param mark
     *            Mark model to be deleted.
     */
    private void deleteMarkOnTable(MarkModel mark) {

        int index = getMarkIndexWithinTheTable(mark);
        deleteOldEditors();
        coordinatesTable.remove(index);

        getMainComposite().refreshMapGraphicLayer();

        mark.deleteObserver(this);
    }

    /**
     * Find the index of this mark model searching all the table items.
     * 
     * @param mark
     *            The mark model.
     * @return The index.
     */
    private int getMarkIndexWithinTheTable(MarkModel mark) {

        int index = -1;
        // find this mark on the table
        TableItem[] items = coordinatesTable.getItems();
        for (TableItem item : items) {
            index++;
            MarkModel itemMark = (MarkModel) item.getData();

            if (mark.equals(itemMark)) {
                break;
            }
        }

        assert index != -1 : "index can't be null, it must have found the given mark."; //$NON-NLS-1$

        return index;
    }

    /**
     * Delete all the marks from the coordinate table.
     */
    private void deleteAllMarksOnTable() {

        deleteOldEditors();
        TableItem[] items = coordinatesTable.getItems();
        coordinatesTable.remove(0, items.length - 1);

        assert coordinatesTable.getItems().length == 0;

        getMainComposite().getMapMarkGraphic().clear();
    }

    /**
     * Add a coordinate into table when mark associated to this table item
     * doesn't have any coordinate value stored.
     * 
     * @param item
     *            Table item
     * @param newCoord
     *            Coordinate to be added.
     * @return True when the coordinate was added into the table.
     */
    private boolean addCoordinateOnTable(TableItem item, Coordinate newCoord, boolean existSelection) {

        MarkModel mark = (MarkModel) item.getData();

        if (existSelection) {

            createEditorsAndSetText(mark, item, newCoord);

            setRowData(item, mark, newCoord);

        } else if (mark.getXCoord().equals(Double.NaN) && mark.getYCoord().equals(Double.NaN)) { // if
            // marks
            // are
            // empty.

            setRowData(item, mark, newCoord);
            return true;
        }

        return false;
    }

    /**
     * Set the data of the given coordinate in the mark model and in the table.
     * 
     * @param item
     *            Table item.
     * @param mark
     *            MarkModel model.
     * @param newCoord
     *            The coordinate containing the data.
     */
    private void setRowData(TableItem item, MarkModel mark, Coordinate newCoord) {

        if (!(Double.isNaN(newCoord.x))) {
            item.setText(1, String.valueOf(newCoord.x));
        } else {
            item.setText(1, ""); //$NON-NLS-1$
        }
        if (!(Double.isNaN(newCoord.y))) {
            item.setText(2, String.valueOf(newCoord.y));
        } else {
            item.setText(2, ""); //$NON-NLS-1$
        }

        mark.setXCoord(newCoord.x);
        mark.setYCoord(newCoord.y);
        // evaluate preconditions
        this.cmd.evalPrecondition();
    }

    /**
     * The first time, adds the listeners.
     */
    public void setContext(IToolContext newContext) {

        if (this.toolContext == null) {
            // add the listener the first time.
            getMainComposite().getMapMarkGraphic().addMouseSelectionListener(mapSelectionListener);
            getMainComposite().addMouseSelectionListenerToImgComposite(imageSelectionListener);
        }
        this.toolContext = newContext;

        if (toolContext != null) {

            // display the map
            IMap map = toolContext.getMap();
            mapLabel.setText("Map: " + map.getName()); //$NON-NLS-1$
            // display the CRS.
            CoordinateReferenceSystem crs = getCurrentMapCrs(map);
            crsLabel.setText("CRS: " + crs.getName().toString()); //$NON-NLS-1$
        }

    }

    /**
     * @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;
    }

    /**
     * Remove all the listeners of the tools and de-activates them.
     * 
     * @param mainComposite
     *            The main composite.
     */
    public void close(MainComposite mainComposite) {

        // remove the listener
        this.coordTool.removeCapturedCoordinateListener(this.capturedListener);
        this.deleteTool.removeDeletedCoordinateListener(this.deletedListener);
        this.moveTool.removeMoveCoordinateListener(this.moveListener);

        this.coordTool.setActive(false);
        this.deleteTool.setActive(false);
        this.moveTool.setActive(false);

        if (this.toolContext != null) {// & !isDisposed()) {
            // delete the listener
            mainComposite.getMapMarkGraphic().deleteMouseSelectionListener(mapSelectionListener);
            mainComposite.deleteMouseSelectionListenerToImgComposite(imageSelectionListener);
        }
    }

    @Override
    public void setEnabled(boolean enabled) {

        this.coordinatesTable.setEnabled(enabled);
        if (this.editorX.getEditor() != null && !this.editorX.getEditor().isDisposed()) {
            this.editorX.getEditor().setEnabled(enabled);
        }
        if (this.editorY.getEditor() != null && !this.editorY.getEditor().isDisposed()) {
            this.editorY.getEditor().setEnabled(enabled);
        }

        setItemsEnabled(enabled);
        setCertainItemsEnabled(enabled);

        super.setEnabled(enabled);
    }

    /**
     * <p>
     * When a mouse_down event occur, gets all the map presenters and search if
     * any of these presenters are affected by the event. If any of the
     * presenter returns true, this mark coordinate data will be deleted from
     * the table and from the mark model.
     * 
     * If the event is not a mouse_down, delegates the event to the
     * {@link MapMarksGraphics}.
     * </p>
     * 
     * @param point
     *            Map point where it was clicked.
     * @param event
     *            Input event.
     */
    private void deleteFromTable(java.awt.Point point, InputEvent event) {

        if (InputEvent.MOUSE_DOWN.equals(event)) {
            // get the presenters
            Map<String, MarkMapPresenter> presenters = getMainComposite().getMapMarkGraphic().getPresenters();

            // iterate the presenters and see if the point belongs to any mark
            MarkModel mark = null;
            Set<Entry<String, MarkMapPresenter>> entrySet = presenters.entrySet();
            Iterator<Entry<String, MarkMapPresenter>> iter = entrySet.iterator();
            while (iter.hasNext()) {

                Entry<String, MarkMapPresenter> entry = iter.next();
                MarkMapPresenter mapPresenter = entry.getValue();

                if (mapPresenter.eventHandler(InputEvent.DELETE, point.x, point.y)) {
                    mark = mapPresenter.getMarkModel();
                    break;
                }
            }

            if (mark != null) {

                deleteOldEditors();

                int index = getMarkIndexWithinTheTable(mark);
                TableItem item = coordinatesTable.getItem(index);

                item.setText(1, ""); //$NON-NLS-1$
                item.setText(2, ""); //$NON-NLS-1$

                mark.setXCoord(Double.NaN);
                mark.setYCoord(Double.NaN);

                this.cmd.evalPrecondition();
                getMainComposite().refreshMapGraphicLayer();

            }
        } else {
            getMainComposite().getMapMarkGraphic().eventhandler(event, point);
        }
    }

    /**
     * Delegate the move event to the {@link MapMarksGraphics}.
     * 
     * @param point
     *            Map point where it was clicked.
     * @param event
     *            Input event.
     */
    private void moveFromTable(java.awt.Point point, InputEvent event) {

        // the mapMarkGraphics will be the responsible to handle these
        // behaviours
        getMainComposite().getMapMarkGraphic().eventhandler(event, point);
    }

    /**
     * Selects the row corresponding to the given mark.
     * 
     * @param mark
     *            MarkModel
     */
    private void selectRow(MarkModel mark) {

        deleteOldEditors();

        int index = getMarkIndexWithinTheTable(mark);
        assert index >= 0;
        coordinatesTable.setSelection(index);

        createEditorColumnX(mark, coordinatesTable.getSelection()[0]);
        createEditorColumnY(mark, coordinatesTable.getSelection()[0]);
    }

    /**
     * If a row is selected and it owns the given mark model, it'll deselect it.
     * 
     * @param mark
     *            The mark model.
     */
    private void deselectRow(MarkModel mark) {

        int index = getMarkIndexWithinTheTable(mark);
        int selection = coordinatesTable.getSelectionIndex();
        if (index == selection) {
            coordinatesTable.deselect(selection);
            deleteOldEditors();
        }

    }

    /**
     * Adds a {@link MouseSelectionListener}.
     * 
     * @param listener
     *            The listener.
     */
    public void addMouseSelectionListener(MouseSelectionListener listener) {

        listeners.add(listener);
    }

    /**
     * Deletes a {@link MouseSelectionListener}.
     * 
     * @param listener
     *            The listener.
     */
    public void deleteMouseSelectionListener(MouseSelectionListener listener) {

        listeners.remove(listener);
    }

    /**
     * Broadcast to all its listeners that the given mark has been selected in
     * the coordinate table.
     * 
     * @param mark
     *            The mark model
     */
    private void broadcastSelectionInEvent(MarkModel mark) {

        for (MouseSelectionListener listener : listeners) {
            listener.inEvent(mark);
        }
    }

    private void deleteAllGCP() {

        Coordinate emptyCoord = new Coordinate(Double.NaN, Double.NaN);
        TableItem[] items = this.coordinatesTable.getItems();
        for (TableItem item : items) {
            MarkModel itemMark = (MarkModel) item.getData();
            itemMark.updateCoordinatePosition(emptyCoord);

        }

        getMainComposite().refreshMapGraphicLayer();
    }
}