net.tourbook.srtm.PrefPageSRTMColors.java Source code

Java tutorial

Introduction

Here is the source code for net.tourbook.srtm.PrefPageSRTMColors.java

Source

/*******************************************************************************
 * Copyright (C) 2005, 2014  Wolfgang Schramm and Contributors
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation version 2 of the License.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 *******************************************************************************/
/**
 * @author Wolfgang Schramm
 * @author Alfred Barten
 */
package net.tourbook.srtm;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import net.tourbook.application.TourbookPlugin;
import net.tourbook.common.UI;
import net.tourbook.common.color.RGBVertex;
import net.tourbook.common.util.ColumnDefinition;
import net.tourbook.common.util.ColumnManager;
import net.tourbook.common.util.ITourViewer;
import net.tourbook.common.util.TableColumnDefinition;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import de.byteholder.geoclipse.map.TileImageCache;
import de.byteholder.geoclipse.mapprovider.MP;

public final class PrefPageSRTMColors extends PreferencePage implements IWorkbenchPreferencePage, ITourViewer {

    private static final String PROFILE_FILE_NAME = "srtmprofiles.xml"; //$NON-NLS-1$
    private static final String PROFILE_XML_ROOT = "srtmprofiles"; //$NON-NLS-1$

    private static final String MEMENTO_CHILD_PROFILE = "profile"; //$NON-NLS-1$
    private static final String TAG_PROFILE_ID = "profileId"; //$NON-NLS-1$
    private static final String TAG_NAME = "name"; //$NON-NLS-1$
    private static final String TAG_IMAGE_PATH = "imagePath"; //$NON-NLS-1$
    private static final String TAG_IS_SHADOW = "isShadow"; //$NON-NLS-1$
    private static final String TAG_SHADOW_VALUE = "shadowValue"; //$NON-NLS-1$
    private static final String TAG_RESOLUTION = "resolution"; //$NON-NLS-1$

    private static final String MEMENTO_CHILD_VERTEX = "vertex"; //$NON-NLS-1$
    private static final String TAG_ALTITUDE = "altitude"; //$NON-NLS-1$
    private static final String TAG_RED = "red"; //$NON-NLS-1$
    private static final String TAG_GREEN = "green"; //$NON-NLS-1$
    private static final String TAG_BLUE = "blue"; //$NON-NLS-1$

    private final static IPreferenceStore _prefStore = TourbookPlugin.getPrefStore();
    private final IDialogSettings _state = TourbookPlugin.getState("SRTMColors"); //$NON-NLS-1$

    private static ArrayList<SRTMProfile> _profileList = new ArrayList<SRTMProfile>();
    private static SRTMProfile _selectedProfile = null;

    private Button _btnEditProfile;
    private Button _btnAddProfile = null;
    private Button _btnRemoveProfile = null;
    private Button _btnDuplicateProfile;

    private int _defaultImageWidth = 300;
    private int _imageHeight = 40;

    private int _oldImageWidth = -1;
    private Composite _viewerContainer;

    private CheckboxTableViewer _profileViewer;
    private ColumnManager _columnManager;

    /**
     * contains the table column widget for the profile color
     */
    private TableColumn _tcProfileImage;

    private TableColumnDefinition _colDefImage;

    /**
     * index of the profile image, this can be changed when the columns are reordered with the mouse
     * or the column manager
     */
    private int _profileImageColumn = 0;

    private BooleanFieldEditor _booleanEditorApplyOption;
    private PixelConverter _pc;

    private static int _maxProfileId;

    private static boolean _isCreateDefault;

    private class ProfileContentProvider implements IStructuredContentProvider {

        @Override
        public void dispose() {
        }

        @Override
        public Object[] getElements(final Object inputElement) {
            return _profileList.toArray(new SRTMProfile[_profileList.size()]);
        }

        @Override
        public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
        }

    }

    public class ProfileSorter extends ViewerSorter {
        @Override
        public int compare(final Viewer viewer, final Object obj1, final Object obj2) {
            return ((SRTMProfile) obj1).getProfileName().compareTo(((SRTMProfile) obj2).getProfileName());
        }
    }

    /**
     * save default profile into a xml file
     * 
     * @return Returns the file which was created to save the default srtm profiles
     */
    private static File createXmlDefaultProfiles() {

        BufferedWriter writer = null;
        final File file = getProfileFile();

        try {

            int profileId = -1;

            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); //$NON-NLS-1$

            final XMLMemento xmlRoot = getXMLRoot();

            IMemento profile = createXmlProfile(xmlRoot, //
                    ++profileId, "Default 1", //$NON-NLS-1$
                    "profile-default-1", //$NON-NLS-1$
                    SRTMProfile.DEFAULT_IS_SHADOW, SRTMProfile.DEFAULT_SHADOW_VALUE,
                    SRTMProfile.DEFAULT_SRTM_RESOLUTION);
            createXmlVertex(profile, -9000, 2, 10, 31);
            createXmlVertex(profile, -1, 14, 76, 255);
            createXmlVertex(profile, 0, 0, 156, 0);
            createXmlVertex(profile, 200, 204, 204, 153);
            createXmlVertex(profile, 400, 204, 153, 0);
            createXmlVertex(profile, 600, 126, 91, 0);
            createXmlVertex(profile, 1000, 127, 127, 128);
            createXmlVertex(profile, 2000, 223, 223, 240);
            createXmlVertex(profile, 8000, 255, 255, 255);

            profile = createXmlProfile(xmlRoot, //
                    ++profileId, "Default 2", //$NON-NLS-1$
                    "profile-default-2", //$NON-NLS-1$
                    SRTMProfile.DEFAULT_IS_SHADOW, SRTMProfile.DEFAULT_SHADOW_VALUE,
                    SRTMProfile.DEFAULT_SRTM_RESOLUTION);
            createXmlVertex(profile, -9000, 2, 10, 31);
            createXmlVertex(profile, -1, 14, 76, 255);
            createXmlVertex(profile, 100, 179, 244, 129);
            createXmlVertex(profile, 200, 144, 239, 129);
            createXmlVertex(profile, 300, 104, 225, 172);
            createXmlVertex(profile, 400, 113, 207, 57);
            createXmlVertex(profile, 500, 255, 255, 0);
            createXmlVertex(profile, 600, 255, 153, 0);
            createXmlVertex(profile, 700, 153, 0, 0);
            createXmlVertex(profile, 800, 255, 0, 51);
            createXmlVertex(profile, 900, 255, 204, 204);
            createXmlVertex(profile, 1000, 204, 255, 255);

            profile = createXmlProfile(xmlRoot, //
                    ++profileId, "Default 3", //$NON-NLS-1$
                    "profile-default-3", //$NON-NLS-1$
                    SRTMProfile.DEFAULT_IS_SHADOW, SRTMProfile.DEFAULT_SHADOW_VALUE,
                    SRTMProfile.DEFAULT_SRTM_RESOLUTION);
            createXmlVertex(profile, -9000, 2, 10, 31);
            createXmlVertex(profile, -1, 14, 76, 255);
            createXmlVertex(profile, 0, 14, 76, 255);
            createXmlVertex(profile, 500, 166, 219, 156);
            createXmlVertex(profile, 1000, 51, 153, 0);
            createXmlVertex(profile, 2000, 102, 51, 0);
            createXmlVertex(profile, 3000, 51, 51, 51);
            createXmlVertex(profile, 4000, 204, 255, 255);
            createXmlVertex(profile, 8850, 255, 255, 255);

            profile = createXmlProfile(xmlRoot, //
                    ++profileId, "Default 4", //$NON-NLS-1$
                    "profile-default-4", //$NON-NLS-1$
                    SRTMProfile.DEFAULT_IS_SHADOW, SRTMProfile.DEFAULT_SHADOW_VALUE,
                    SRTMProfile.DEFAULT_SRTM_RESOLUTION);
            createXmlVertex(profile, -9000, 2, 10, 31);
            createXmlVertex(profile, -1, 14, 76, 255);
            createXmlVertex(profile, 0, 255, 255, 255);
            createXmlVertex(profile, 1000, 178, 81, 0);
            createXmlVertex(profile, 2000, 100, 0, 59);
            createXmlVertex(profile, 3000, 0, 102, 127);

            profile = createXmlProfile(xmlRoot, //
                    ++profileId, "Default 5", //$NON-NLS-1$
                    "profile-default-5", //$NON-NLS-1$
                    SRTMProfile.DEFAULT_IS_SHADOW, SRTMProfile.DEFAULT_SHADOW_VALUE,
                    SRTMProfile.DEFAULT_SRTM_RESOLUTION);
            createXmlVertex(profile, -9000, 2, 10, 31);
            createXmlVertex(profile, -1, 14, 76, 255);
            createXmlVertex(profile, 0, 0, 0, 255);
            createXmlVertex(profile, 1000, 127, 0, 215);
            createXmlVertex(profile, 2000, 255, 0, 0);
            createXmlVertex(profile, 3000, 195, 103, 0);
            createXmlVertex(profile, 4000, 190, 193, 0);
            createXmlVertex(profile, 5000, 122, 190, 0);
            createXmlVertex(profile, 6000, 20, 141, 0);
            createXmlVertex(profile, 7000, 105, 231, 202);
            createXmlVertex(profile, 8000, 255, 255, 255);

            profile = createXmlProfile(xmlRoot, //
                    ++profileId, "Default 6", //$NON-NLS-1$
                    "profile-default-6", //$NON-NLS-1$
                    SRTMProfile.DEFAULT_IS_SHADOW, SRTMProfile.DEFAULT_SHADOW_VALUE,
                    SRTMProfile.DEFAULT_SRTM_RESOLUTION);
            createXmlVertex(profile, -9000, 2, 10, 31);
            createXmlVertex(profile, -1, 14, 76, 255);
            createXmlVertex(profile, 0, 255, 255, 255);
            createXmlVertex(profile, 100, 92, 43, 0);
            createXmlVertex(profile, 150, 166, 77, 0);
            createXmlVertex(profile, 200, 106, 148, 0);
            createXmlVertex(profile, 250, 35, 161, 48);
            createXmlVertex(profile, 300, 54, 134, 255);
            createXmlVertex(profile, 350, 130, 255, 255);

            xmlRoot.save(writer);

        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (final IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return file;
    }

    private static IMemento createXmlProfile(final XMLMemento xmlMemento, final int profileId, final String name,
            final String profileImagePath, final boolean isShadow, final float shadowValue,
            final String resolution) {

        final IMemento xmlProfile = xmlMemento.createChild(MEMENTO_CHILD_PROFILE);

        xmlProfile.putInteger(TAG_PROFILE_ID, profileId);
        xmlProfile.putString(TAG_NAME, name);
        xmlProfile.putString(TAG_IMAGE_PATH, profileImagePath);
        xmlProfile.putBoolean(TAG_IS_SHADOW, isShadow);
        xmlProfile.putString(TAG_RESOLUTION, resolution);
        xmlProfile.putFloat(TAG_SHADOW_VALUE, shadowValue);

        return xmlProfile;
    }

    private static void createXmlVertex(final IMemento mementoProfile, final int altitude, final int red,
            final int green, final int blue) {

        final IMemento xmlVertex = mementoProfile.createChild(MEMENTO_CHILD_VERTEX);
        xmlVertex.putInteger(TAG_ALTITUDE, altitude);
        xmlVertex.putInteger(TAG_RED, red);
        xmlVertex.putInteger(TAG_GREEN, green);
        xmlVertex.putInteger(TAG_BLUE, blue);
    }

    private static void disposeProfileImages() {
        for (final SRTMProfile profile : _profileList) {
            if (profile != null) {
                profile.disposeImage();
            }
        }
    }

    private static File getProfileFile() {
        final IPath stateLocation = Platform.getStateLocation(TourbookPlugin.getDefault().getBundle());
        return stateLocation.append(PROFILE_FILE_NAME).toFile();
    }

    public static SRTMProfile getSelectedProfile() {
        return _selectedProfile;
    }

    private static XMLMemento getXMLRoot() {

        try {

            final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

            // create root element
            final Element element = document.createElement(PROFILE_XML_ROOT);
            element.setAttribute("version", "1"); //$NON-NLS-1$ //$NON-NLS-2$
            document.appendChild(element);

            return new XMLMemento(document, element);

        } catch (final ParserConfigurationException e) {
            throw new Error(e.getMessage());
        }
    }

    /**
     * load profiles and set profile to the previous profile
     */
    public static void initVertexLists() {
        loadProfiles();
        restoreSelectedProfile();
    }

    /**
     * load profiles from profile file
     */
    private static void loadProfiles() {

        // cleanup existing profiles
        disposeProfileImages();
        _profileList.clear();

        /*
         * get profile file
         */

        final IPath stateLocation = Platform.getStateLocation(TourbookPlugin.getDefault().getBundle());
        File profileFile = stateLocation.append(PROFILE_FILE_NAME).toFile();

        if (profileFile.exists() == false) {

            /*
             * check if the file exists in the old location from version <= 10.3
             */

            final IPath stateRoot = stateLocation.removeLastSegments(1);
            final IPath oldFilePath = stateRoot.append("net.tourbook.srtm"); //$NON-NLS-1$

            profileFile = oldFilePath.append(PROFILE_FILE_NAME).toFile();
        }

        // check if file is available
        if (profileFile.exists() == false) {

            // create default profile
            final File createdProfileFile = createXmlDefaultProfiles();

            // check again after the file was created
            if (createdProfileFile.exists() == false) {
                MessageDialog.openError(Display.getCurrent().getActiveShell(), //
                        "Default Profile", //$NON-NLS-1$
                        NLS.bind("SRTM color profile file {0} could not be created", //$NON-NLS-1$
                                profileFile.getAbsolutePath()));
                return;
            }

            profileFile = createdProfileFile;
        }

        InputStreamReader reader = null;

        try {

            final ArrayList<RGBVertex> vertexList = new ArrayList<RGBVertex>();
            _maxProfileId = -1;

            reader = new InputStreamReader(new FileInputStream(profileFile), "UTF-8"); //$NON-NLS-1$
            final XMLMemento xmlRoot = XMLMemento.createReadRoot(reader);

            /*
             * read all profiles
             */
            final IMemento[] xmlProfiles = xmlRoot.getChildren(MEMENTO_CHILD_PROFILE);
            for (final IMemento xmlProfile : xmlProfiles) {

                /*
                 * read profile properties
                 */
                final Integer profileId = xmlProfile.getInteger(TAG_PROFILE_ID);
                if (profileId == null) {
                    continue;
                }

                final String profileName = xmlProfile.getString(TAG_NAME);
                if (profileName == null) {
                    continue;
                }

                final String profilePath = xmlProfile.getString(TAG_IMAGE_PATH);
                if (profilePath == null) {
                    continue;
                }

                final Boolean profileShadowState = xmlProfile.getBoolean(TAG_IS_SHADOW);
                if (profileShadowState == null) {
                    continue;
                }

                Float profileShadowValue = xmlProfile.getFloat(TAG_SHADOW_VALUE);
                if (profileShadowValue == null) {
                    // set default value
                    profileShadowValue = SRTMProfile.DEFAULT_SHADOW_VALUE;
                }

                final String profileResolution = xmlProfile.getString(TAG_RESOLUTION);
                if (profileResolution == null) {
                    continue;
                }

                /*
                 * read all vertexes
                 */
                vertexList.clear();
                final IMemento[] xmlVertexes = xmlProfile.getChildren(MEMENTO_CHILD_VERTEX);
                for (final IMemento xmlVertex : xmlVertexes) {

                    final Integer altitude = xmlVertex.getInteger(TAG_ALTITUDE);
                    if (altitude == null) {
                        continue;
                    }
                    final Integer red = xmlVertex.getInteger(TAG_RED);
                    if (red == null) {
                        continue;
                    }
                    final Integer green = xmlVertex.getInteger(TAG_GREEN);
                    if (green == null) {
                        continue;
                    }
                    final Integer blue = xmlVertex.getInteger(TAG_BLUE);
                    if (blue == null) {
                        continue;
                    }

                    vertexList.add(new RGBVertex(altitude, red, green, blue));
                }

                /*
                 * create profile
                 */
                SRTMProfile profile;
                _profileList.add(profile = new SRTMProfile());

                profile.setProfileId(profileId);
                profile.setProfileName(profileName);
                profile.setTilePath(profilePath);
                profile.setShadowState(profileShadowState);
                profile.setShadowValue(profileShadowValue);
                profile.setResolution(profileResolution);

                profile.setVertices(vertexList);

                // get max profile id
                _maxProfileId = Math.max(_maxProfileId, profileId);
            }

        } catch (final UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (final FileNotFoundException e) {
            e.printStackTrace();
        } catch (final WorkbenchException e) {
            e.printStackTrace();
        } catch (final NumberFormatException e) {
            e.printStackTrace();
        } finally {

            if (reader != null) {
                try {
                    reader.close();
                } catch (final IOException e) {
                    e.printStackTrace();
                }
            }

            if (_profileList.size() == 0) {

                // !!! this message is confusing the user !!!
                //            MessageDialog.openError(Display.getCurrent().getActiveShell(), //
                //                  "Read Profiles", //$NON-NLS-1$
                //                  "SRTM color profile is not available, default profile is created."); //$NON-NLS-1$

                // prevent endless loops
                if (_isCreateDefault) {
                    _isCreateDefault = false;
                } else {

                    // create default profile
                    createXmlDefaultProfiles();

                    _isCreateDefault = true;
                    loadProfiles();
                }

            } else {

                // create profile key for the saved profile
                for (final SRTMProfile profile : _profileList) {
                    profile.createSavedProfileKey();
                }
            }
        }
    }

    private static void restoreSelectedProfile() {

        /*
         * get selected profile
         */
        final int prefProfileId = _prefStore.getInt(IPreferences.SRTM_COLORS_SELECTED_PROFILE_ID);
        for (final SRTMProfile profile : _profileList) {
            if (profile.getProfileId() == prefProfileId) {
                _selectedProfile = profile;
                break;
            }
        }
        if (_selectedProfile == null) {
            // set default profile
            _selectedProfile = _profileList.get(0);
        }
    }

    @Override
    protected Control createContents(final Composite parent) {

        initVertexLists();

        _pc = new PixelConverter(parent);

        final Composite container = createUI(parent);

        reloadViewer();

        restoreState();

        // reselected profile
        selectProfileInViewer(_selectedProfile);

        enableActions();

        return container;
    }

    /**
     * Creates a new profile which is not yet attached to the model
     * 
     * @return
     */
    private SRTMProfile createNewProfile() {

        final SRTMProfile profile = new SRTMProfile();

        final int newProfileId = ++_maxProfileId;

        profile.setProfileId(newProfileId);
        profile.setProfileName(Messages.prefPage_srtm_default_profile_name);

        // make a unique tile path
        profile.setTilePath(Messages.prefPage_srtm_default_profile_path + "-" + newProfileId);//$NON-NLS-1$

        profile.setDefaultVertexes();

        return profile;
    }

    private Composite createUI(final Composite parent) {

        final Composite container = new Composite(parent, SWT.NONE);
        GridDataFactory.swtDefaults().grab(true, true).applyTo(container);
        GridLayoutFactory.fillDefaults().applyTo(container);
        {
            final Composite profileContainer = new Composite(container, SWT.NONE);
            GridDataFactory.fillDefaults().grab(true, true).applyTo(profileContainer);
            GridLayoutFactory.fillDefaults().numColumns(2).extendedMargins(0, 0, 0, 0).applyTo(profileContainer);
            {
                createUI_10_ProfileViewer_Container(profileContainer);
                createUI_20_Actions(profileContainer);
            }
        }

        createUI_30_ApplyOption(parent);

        return container;
    }

    private void createUI_10_ProfileViewer_Container(final Composite parent) {

        // define all columns for the viewer
        _columnManager = new ColumnManager(this, _state);
        defineAllColumns();

        _viewerContainer = new Composite(parent, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(_viewerContainer);
        GridLayoutFactory.fillDefaults().applyTo(_viewerContainer);
        {
            createUI_12_ProfileViewer_Table(_viewerContainer);
        }
    }

    private void createUI_12_ProfileViewer_Table(final Composite parent) {

        final Table table = new Table(parent,
                SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.CHECK);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(table);

        table.setLayout(new TableLayout());
        table.setHeaderVisible(true);

        /*
         * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly. Therefore, it is
         * critical for performance that these methods be as efficient as possible.
         */
        final Listener paintListener = new Listener() {
            @Override
            public void handleEvent(final Event event) {

                if (event.index == _profileImageColumn) {
                    onPaintColorImage(event);
                }
            }
        };
        table.addListener(SWT.MeasureItem, paintListener);
        table.addListener(SWT.PaintItem, paintListener);

        /*
         * create viewer
         */
        _profileViewer = new CheckboxTableViewer(table);

        _columnManager.createColumns(_profileViewer);

        _tcProfileImage = _colDefImage.getTableColumn();
        _profileImageColumn = _colDefImage.getCreateIndex();

        _profileViewer.setContentProvider(new ProfileContentProvider());
        _profileViewer.setSorter(new ProfileSorter());

        _profileViewer.addCheckStateListener(new ICheckStateListener() {
            @Override
            public void checkStateChanged(final CheckStateChangedEvent event) {

                final SRTMProfile checkedProfile = (SRTMProfile) event.getElement();

                // ignore the same profile
                if (_selectedProfile != null && checkedProfile == _selectedProfile) {

                    // prevent unchecking selected profile
                    event.getCheckable().setChecked(checkedProfile, true);

                    return;
                }

                // select checked profile
                selectProfileInViewer(checkedProfile);
            }
        });

        _profileViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(final SelectionChangedEvent event) {

                final Object firstElement = ((StructuredSelection) event.getSelection()).getFirstElement();
                if (firstElement instanceof SRTMProfile) {
                    onSelectProfile((SRTMProfile) firstElement, false);
                }
            }
        });

        _profileViewer.addDoubleClickListener(new IDoubleClickListener() {
            @Override
            public void doubleClick(final DoubleClickEvent event) {
                onEditProfile();
            }
        });

    }

    private void createUI_20_Actions(final Composite parent) {

        final Composite container = new Composite(parent, SWT.NONE);
        GridDataFactory.fillDefaults().applyTo(container);
        GridLayoutFactory.fillDefaults().applyTo(container);
        {
            /*
             * button: edit profile
             */
            _btnEditProfile = new Button(container, SWT.NONE);
            _btnEditProfile.setText(Messages.prefPage_srtm_profile_edit);
            _btnEditProfile.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent e) {
                    onEditProfile();
                }
            });
            setButtonLayoutData(_btnEditProfile);

            /*
             * button: add profile
             */
            _btnAddProfile = new Button(container, SWT.NONE);
            _btnAddProfile.setText(Messages.prefPage_srtm_profile_add);
            _btnAddProfile.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent e) {
                    onAddProfile();
                }
            });
            setButtonLayoutData(_btnAddProfile);

            /*
             * button: remove profile
             */
            _btnRemoveProfile = new Button(container, SWT.NONE);
            _btnRemoveProfile.setText(Messages.prefPage_srtm_profile_remove);
            _btnRemoveProfile.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent e) {
                    onRemoveProfile();
                }
            });
            setButtonLayoutData(_btnRemoveProfile);

            /*
             * button: duplicate profile
             */
            _btnDuplicateProfile = new Button(container, SWT.NONE);
            _btnDuplicateProfile.setText(Messages.prefPage_srtm_profile_duplicate);
            _btnDuplicateProfile.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent e) {
                    onDuplicateProfile();
                }
            });
            setButtonLayoutData(_btnDuplicateProfile);

            /*
             * button: adjust columns
             */
            final Button btnAdjustColumns = new Button(container, SWT.NONE);
            btnAdjustColumns.setText(Messages.prefPage_srtm_btn_adjust_columns);
            btnAdjustColumns.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent e) {
                    _columnManager.openColumnDialog();
                }
            });
            setButtonLayoutData(btnAdjustColumns);
            final GridData gd = (GridData) btnAdjustColumns.getLayoutData();
            gd.verticalIndent = 20;
        }
    }

    private void createUI_30_ApplyOption(final Composite parent) {

        /*
         * checkbox: pace min/max value
         */
        _booleanEditorApplyOption = new BooleanFieldEditor(IPreferences.SRTM_APPLY_WHEN_PROFILE_IS_SELECTED,
                Messages.prefPage_srtm_profile_option_apply_when_selected, parent);
        _booleanEditorApplyOption.setPreferenceStore(_prefStore);
        _booleanEditorApplyOption.setPage(this);
        _booleanEditorApplyOption.setPropertyChangeListener(new IPropertyChangeListener() {
            @Override
            public void propertyChange(final PropertyChangeEvent event) {
                if (((Boolean) event.getNewValue())) {
                    // apply profile
                    final Object firstElement = ((StructuredSelection) _profileViewer.getSelection())
                            .getFirstElement();
                    if (firstElement instanceof SRTMProfile) {
                        onSelectProfile((SRTMProfile) firstElement, true);
                    }
                }
            }
        });
    }

    private void defineAllColumns() {

        defineColumn_ColorImage();
        defineColumn_ProfileId();
        defineColumn_ProfileName();
        defineColumn_Resolution();
        defineColumn_ShadowState();
        defineColumn_ShadowValue();
        defineColumn_TileImagePath();
    }

    /**
     * Column: Color image
     */
    private void defineColumn_ColorImage() {

        final TableColumnDefinition colDef = new TableColumnDefinition(_columnManager, "color", SWT.LEAD); //$NON-NLS-1$
        _colDefImage = colDef;

        colDef.setColumnLabel(Messages.profileViewer_column_label_color);
        colDef.setColumnHeaderText(Messages.profileViewer_column_label_color_header);
        colDef.setColumnHeaderToolTipText(Messages.profileViewer_column_label_color_tooltip);
        colDef.setDefaultColumnWidth(_pc.convertWidthInCharsToPixels(50));
        colDef.setIsDefaultColumn();
        colDef.setCanModifyVisibility(false);
        colDef.setLabelProvider(new CellLabelProvider() {
            /*
             * !!! set dummy label provider, otherwise an error occures !!!
             */
            @Override
            public void update(final ViewerCell cell) {
            }
        });

        colDef.setControlListener(new ControlAdapter() {
            @Override
            public void controlResized(final ControlEvent e) {
                onResizeImageColumn();
            }
        });
    }

    /**
     * column: id
     */
    private void defineColumn_ProfileId() {

        final TableColumnDefinition colDef = new TableColumnDefinition(_columnManager, "profileId", SWT.TRAIL); //$NON-NLS-1$

        colDef.setColumnLabel(Messages.profileViewer_column_label_id);
        colDef.setColumnHeaderText(Messages.profileViewer_column_label_id_header);
        colDef.setColumnHeaderToolTipText(Messages.profileViewer_column_label_id_tooltip);
        colDef.setDefaultColumnWidth(_pc.convertWidthInCharsToPixels(10));
        colDef.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(final ViewerCell cell) {

                final SRTMProfile vertexList = (SRTMProfile) cell.getElement();
                cell.setText(Integer.toString(vertexList.getProfileId()));
            }
        });
    }

    /**
     * column: profile name
     */
    private void defineColumn_ProfileName() {

        final TableColumnDefinition colDef = new TableColumnDefinition(_columnManager, "profileName", SWT.LEAD); //$NON-NLS-1$

        colDef.setColumnLabel(Messages.profileViewer_column_label_name);
        colDef.setColumnHeaderText(Messages.profileViewer_column_label_name_header);
        colDef.setColumnHeaderToolTipText(Messages.profileViewer_column_label_name_tooltip);
        colDef.setDefaultColumnWidth(_pc.convertWidthInCharsToPixels(20));
        colDef.setIsDefaultColumn();
        colDef.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(final ViewerCell cell) {

                final SRTMProfile vertexList = (SRTMProfile) cell.getElement();
                cell.setText(vertexList.getProfileName());
            }
        });
    }

    /**
     * column: resolution
     */
    private void defineColumn_Resolution() {

        final TableColumnDefinition colDef = new TableColumnDefinition(_columnManager, "resolution", SWT.LEAD); //$NON-NLS-1$

        colDef.setColumnLabel(Messages.profileViewer_column_label_resolution);
        colDef.setColumnHeaderText(Messages.profileViewer_column_label_resolution_header);
        colDef.setColumnHeaderToolTipText(Messages.profileViewer_column_label_resolution_tooltip);
        colDef.setDefaultColumnWidth(_pc.convertWidthInCharsToPixels(20));
        colDef.setIsDefaultColumn();
        colDef.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(final ViewerCell cell) {

                final SRTMProfile profile = (SRTMProfile) cell.getElement();
                cell.setText(getResolutionUI(profile));
            }
        });
    }

    /**
     * column: shadow state
     */
    private void defineColumn_ShadowState() {

        final TableColumnDefinition colDef = new TableColumnDefinition(_columnManager, "shadowState", SWT.LEAD); //$NON-NLS-1$

        colDef.setColumnLabel(Messages.profileViewer_column_label_isShadow);
        colDef.setColumnHeaderText(Messages.profileViewer_column_label_isShadow_header);
        colDef.setColumnHeaderToolTipText(Messages.profileViewer_column_label_isShadow_tooltip);
        colDef.setDefaultColumnWidth(_pc.convertWidthInCharsToPixels(5));
        colDef.setIsDefaultColumn();
        colDef.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(final ViewerCell cell) {

                final SRTMProfile profile = (SRTMProfile) cell.getElement();
                cell.setText(profile.isShadowState() ? Messages.app_ui_Y : Messages.app_ui_N);
            }
        });
    }

    /**
     * column: shadow value
     */
    private void defineColumn_ShadowValue() {

        final TableColumnDefinition colDef = new TableColumnDefinition(_columnManager, "shadowValue", SWT.LEAD); //$NON-NLS-1$

        colDef.setColumnLabel(Messages.profileViewer_column_label_shadowValue);
        colDef.setColumnHeaderText(Messages.profileViewer_column_label_shadowValue_header);
        colDef.setColumnHeaderToolTipText(Messages.profileViewer_column_label_shadowValue_tooltip);
        colDef.setDefaultColumnWidth(_pc.convertWidthInCharsToPixels(10));
        colDef.setIsDefaultColumn();
        colDef.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(final ViewerCell cell) {

                final SRTMProfile profile = (SRTMProfile) cell.getElement();
                cell.setText(Float.toString(profile.getShadowValue()));
            }
        });
    }

    /**
     * column: image path
     */
    private void defineColumn_TileImagePath() {

        final TableColumnDefinition colDef = new TableColumnDefinition(_columnManager, "tileImagePath", SWT.LEAD); //$NON-NLS-1$
        colDef.setColumnLabel(Messages.profileViewer_column_label_imagePath);
        colDef.setColumnHeaderText(Messages.profileViewer_column_label_imagePath_header);
        colDef.setColumnHeaderToolTipText(Messages.profileViewer_column_label_imagePath_tooltip);
        colDef.setDefaultColumnWidth(_pc.convertWidthInCharsToPixels(20));
        colDef.setIsDefaultColumn();
        colDef.setLabelProvider(new CellLabelProvider() {
            @Override
            public void update(final ViewerCell cell) {

                final SRTMProfile vertexList = (SRTMProfile) cell.getElement();
                cell.setText(vertexList.getTilePath());
            }
        });
    }

    private void deleteAllOfflineImages() {

        for (final SRTMProfile profile : _profileList) {
            deleteOfflineImages(profile);
        }
    }

    /**
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RECURSIVE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!<br>
     * Deletes all files and subdirectories. If a deletion fails, the method stops attempting to
     * delete and returns false. <br>
     * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RECURSIVE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     * 
     * @param directory
     * @return Returns <code>true</code> if all deletions were successful
     */
    private boolean deleteDir(final File directory) {

        if (directory.isDirectory()) {

            final String[] children = directory.list();

            for (final String element : children) {
                final boolean success = deleteDir(new File(directory, element));
                if (!success) {
                    return false;
                }
            }
        }

        // The directory is now empty so delete it
        final boolean isDeleted = directory.delete();

        return isDeleted;
    }

    /**
     * Delete tile images for the given profile
     * 
     * @param profile
     */
    private void deleteOfflineImages(final SRTMProfile profile) {

        try {

            final MP mp = ElevationColor.getMapProvider();
            if (mp == null) {
                // TODO initialize map provider
                return;
            }

            final IPath tileCacheOSPathFolder = getOfflineFolder(mp);
            if (tileCacheOSPathFolder == null) {
                return;
            }

            // get profile folder
            final File profileFolder = tileCacheOSPathFolder.append(profile.getTilePath()).toFile();
            if (profileFolder.exists() == false) {
                return;
            }

            // check if the folder contains files/folders
            final String[] fileList = profileFolder.list();
            if (fileList == null || fileList.length == 0) {
                return;
            }

            deleteDir(profileFolder);

        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * delete all tile images which profile key has changed
     */
    private void deleteOfflineImagesWhenModified() {

        try {

            final MP mp = ElevationColor.getMapProvider();
            if (mp == null) {
                // TODO initialize map provider
                return;
            }

            final IPath tileCacheOSPathFolder = getOfflineFolder(mp);
            if (tileCacheOSPathFolder == null) {
                return;
            }

            // loop: all profiles
            for (final SRTMProfile profile : _profileList) {
                if (profile.getProfileKeyHashCode() != profile.getSavedProfileKeyHashCode()) {

                    // profile key has changed

                    // get profile folder
                    final File profileFolder = tileCacheOSPathFolder.append(profile.getTilePath()).toFile();
                    if (profileFolder.exists() == false) {
                        continue;
                    }

                    // check if the folder contains files/folders
                    final String[] fileList = profileFolder.list();
                    if (fileList == null || fileList.length == 0) {
                        continue;
                    }

                    deleteDir(profileFolder);
                }
            }

        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void dispose() {
        disposeProfileImages();
        super.dispose();
    }

    @Override
    protected IPreferenceStore doGetPreferenceStore() {
        return TourbookPlugin.getDefault().getPreferenceStore();
    }

    private void editNewProfile(final SRTMProfile newProfile) {

        try {

            // open color chooser dialog

            final DialogSelectSRTMColors dialog = new DialogSelectSRTMColors(Display.getCurrent().getActiveShell(),
                    null, newProfile, _profileList, this, true);

            if (dialog.open() == Window.OK) {
                saveProfileNew(newProfile);
            }

            // image orientation has changed
            disposeProfileImages();

        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    private void enableActions() {

        final StructuredSelection selection = (StructuredSelection) _profileViewer.getSelection();

        _btnRemoveProfile.setEnabled(selection.size() == 1 && _profileList.size() > 1);
    }

    @Override
    public ColumnManager getColumnManager() {
        return _columnManager;
    }

    private int getImageWidth() {

        int width;

        if (_tcProfileImage == null) {
            width = _defaultImageWidth;
        } else {
            width = _tcProfileImage.getWidth();
        }

        return width;
    }

    private IPath getOfflineFolder(final MP mp) {

        IPath tileCacheOSPathFolder = null;

        final String tileCacheOSPath = TileImageCache.getTileCacheOSPath();
        if (tileCacheOSPath != null) {
            tileCacheOSPathFolder = new Path(tileCacheOSPath).append(mp.getOfflineFolder());
        }

        return tileCacheOSPathFolder;
    }

    /**
     * Type of map is changed IFF one of colors, shadow state or grid is changed.
     * 
     * @return Hashcode for the unique key for the current profile settings
     */
    private int getProfileKeyHashCode() {
        return _selectedProfile.getProfileKey().hashCode();
    }

    private String getResolutionUI(final SRTMProfile profile) {

        final String resolution = profile.getResolution();

        if (IPreferences.SRTM_RESOLUTION_VERY_FINE.equals(resolution)) {
            return Messages.profileViewer_column_content_resolution_veryFine;
        } else if (IPreferences.SRTM_RESOLUTION_FINE.equals(resolution)) {
            return Messages.profileViewer_column_content_resolution_fine;
        } else if (IPreferences.SRTM_RESOLUTION_ROUGH.equals(resolution)) {
            return Messages.profileViewer_column_content_resolution_rough;
        } else if (IPreferences.SRTM_RESOLUTION_VERY_ROUGH.equals(resolution)) {
            return Messages.profileViewer_column_content_resolution_veryRough;
        }

        return UI.EMPTY_STRING;
    }

    @Override
    public ColumnViewer getViewer() {
        return _profileViewer;
    }

    @Override
    public void init(final IWorkbench workbench) {
    }

    @Override
    public boolean okToLeave() {

        saveViewerState();

        return super.okToLeave();
    }

    /**
     * create profile
     */
    private void onAddProfile() {

        final SRTMProfile newProfile = createNewProfile();

        editNewProfile(newProfile);
    }

    private void onDuplicateProfile() {

        final SRTMProfile newProfile = _selectedProfile.clone();

        final int newProfileId = ++_maxProfileId;

        newProfile.setProfileId(newProfileId);

        editNewProfile(newProfile);
    }

    private void onEditProfile() {

        final Object firstElement = ((StructuredSelection) _profileViewer.getSelection()).getFirstElement();
        if (firstElement instanceof SRTMProfile) {

            final SRTMProfile originalProfile = (SRTMProfile) firstElement;

            try {

                // open color chooser dialog

                final SRTMProfile dialogProfile = originalProfile.clone();

                final DialogSelectSRTMColors dialog = new DialogSelectSRTMColors(
                        Display.getCurrent().getActiveShell(), originalProfile, dialogProfile, _profileList, this,
                        false);

                if (dialog.open() == Window.OK) {
                    saveProfileModified(originalProfile, dialogProfile);
                }

                // image orientation has changed
                disposeProfileImages();

            } catch (final Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void onPaintColorImage(final Event event) {

        final TableItem item = (TableItem) event.item;
        final SRTMProfile profile = (SRTMProfile) item.getData();

        final Image image = profile.getRgbVertexImage().getValidatedImage(getImageWidth(), _imageHeight, true);

        if (image != null) {

            final Rectangle rect = image.getBounds();

            switch (event.type) {
            case SWT.MeasureItem:

                event.width += rect.width;
                event.height = Math.max(event.height, rect.height + 2);

                break;

            case SWT.PaintItem:

                final int x = event.x + event.width;
                final int offset = Math.max(0, (event.height - rect.height) / 2);
                event.gc.drawImage(image, x, event.y + offset);

                break;
            }
        }
    }

    private void onRemoveProfile() {

        // confirm removal
        if (MessageDialog.openConfirm(Display.getCurrent().getActiveShell(),
                Messages.prefPage_srtm_dlg_delete_profile_title,
                Messages.prefPage_srtm_dlg_delete_profile_msg) == false) {
            return;
        }

        int selectedIndex = _profileViewer.getTable().getSelectionIndex();

        // update model
        _profileList.remove(_selectedProfile);

        // update viewer
        _profileViewer.remove(_selectedProfile);

        // remove images
        deleteOfflineImages(_selectedProfile);
        _selectedProfile.disposeImage();

        /*
         * select a new profile from the same position
         */
        final int profileSize = _profileList.size();
        selectedIndex = selectedIndex >= profileSize ? profileSize - 1 : selectedIndex;
        _selectedProfile = (SRTMProfile) _profileViewer.getElementAt(selectedIndex);

        selectProfileInViewer(_selectedProfile);

        saveAllProfiles();
    }

    private void onResizeImageColumn() {

        final int newImageWidth = getImageWidth();

        // check if the width has changed
        if (newImageWidth == _oldImageWidth) {
            return;
        }

        // recreate images
        disposeProfileImages();
    }

    private void onSelectProfile(final SRTMProfile selectedProfile, final boolean isForceSelection) {

        // ignore same profile
        if (isForceSelection == false && _selectedProfile != null && _selectedProfile == selectedProfile) {
            enableActions();
            return;
        }

        // uncheck previous profile
        if (_selectedProfile != null) {
            _profileViewer.setChecked(_selectedProfile, false);
        }

        // check selected profile
        _selectedProfile = selectedProfile;
        _profileViewer.setChecked(_selectedProfile, true);

        enableActions();

        if (_booleanEditorApplyOption.getBooleanValue()) {

            // apply profile

            saveSelectedProfile();
        }
    }

    @Override
    public boolean performCancel() {

        saveViewerState();

        return super.performCancel();
    }

    @Override
    protected void performDefaults() {

        if (MessageDialog.openConfirm(Display.getCurrent().getActiveShell(),
                Messages.prefPage_srtm_confirm_defaults_title, Messages.prefPage_srtm_confirm_defaults_message)) {

            deleteAllOfflineImages();

            createXmlDefaultProfiles();

            initVertexLists();

            reloadViewer();

            _selectedProfile = _profileList.get(0);
            selectProfileInViewer(_selectedProfile);

            _booleanEditorApplyOption.loadDefault();

            saveState();
        }

        super.performDefaults();
    }

    @Override
    public boolean performOk() {

        saveState();

        return super.performOk();
    }

    @Override
    public ColumnViewer recreateViewer(final ColumnViewer columnViewer) {

        _viewerContainer.setRedraw(false);
        {
            _profileViewer.getTable().dispose();

            createUI_12_ProfileViewer_Table(_viewerContainer);
            _viewerContainer.layout();

            // update the viewer
            reloadViewer();
        }
        _viewerContainer.setRedraw(true);

        return _profileViewer;
    }

    @Override
    public void reloadViewer() {
        _profileViewer.setInput(new Object[0]);
    }

    private void restoreState() {

        _booleanEditorApplyOption.load();
    }

    private void saveAllProfiles() {

        deleteOfflineImagesWhenModified();

        saveProfileXMLFile();

        saveState();
    }

    void saveProfile(final SRTMProfile originalProfile, final SRTMProfile dialogProfile,
            final boolean isNewProfile) {

        if (isNewProfile) {
            saveProfileNew(dialogProfile);
        } else {
            saveProfileModified(originalProfile, dialogProfile);
        }
    }

    /**
     * Save profile which was edited
     * 
     * @param originalProfile
     * @param dialogProfile
     */
    private void saveProfileModified(final SRTMProfile originalProfile, final SRTMProfile dialogProfile) {

        // delete tile images when tile path has changed
        if (originalProfile.getTilePath().equalsIgnoreCase(dialogProfile.getTilePath()) == false) {
            deleteOfflineImages(originalProfile);
        }

        if (originalProfile.equals(dialogProfile) == false) {

            /*
             * when a new profile is applied in the color dialog, both profiles are the same,
             * cloning is not required, it would remove the vertexes
             */
            originalProfile.copyFromOtherProfile(dialogProfile);
        }

        originalProfile.disposeImage();

        // update viewer
        _profileViewer.refresh();
        _profileViewer.setSelection(new StructuredSelection(originalProfile), true);

        saveAllProfiles();

        originalProfile.createSavedProfileKey();
    }

    /**
     * Save profile which was newly created
     * 
     * @param newProfile
     */
    private void saveProfileNew(final SRTMProfile newProfile) {

        /*
         * when a new profile is applied in the color dialog, it is not new anymore
         */
        final int profileIndex = _profileList.indexOf(newProfile);
        if (profileIndex != -1) {

            // save existing profile

            final SRTMProfile newSavedProfile = _profileList.get(profileIndex);
            saveProfileModified(newSavedProfile, newProfile);

        } else {

            // save new profile

            newProfile.createSavedProfileKey();

            // update model
            _profileList.add(newProfile);

            // rotate image
            newProfile.disposeImage();

            // update viewer
            _profileViewer.add(newProfile);

            // select new profile
            _profileViewer.setAllChecked(false);
            selectProfileInViewer(newProfile);

            saveAllProfiles();
        }
    }

    private void saveProfileXMLFile() {

        BufferedWriter writer = null;

        try {

            final File file = getProfileFile();
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")); //$NON-NLS-1$

            final XMLMemento xmlRoot = getXMLRoot();

            for (final SRTMProfile profile : _profileList) {

                final IMemento xmlProfile = createXmlProfile(xmlRoot, profile.getProfileId(),
                        profile.getProfileName(), profile.getTilePath(), profile.isShadowState(),
                        profile.getShadowValue(), profile.getResolution());

                for (final RGBVertex vertex : profile.getRgbVertexImage().getRgbVertices()) {

                    final RGB rgb = vertex.getRGB();

                    createXmlVertex(xmlProfile, vertex.getValue(), rgb.red, rgb.green, rgb.blue);
                }
            }

            xmlRoot.save(writer);

        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (final IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * save selected profile, this will fire an event to update existing maps
     */
    private void saveSelectedProfile() {
        if (_selectedProfile != null) {

            _prefStore.setValue(IPreferences.SRTM_COLORS_SELECTED_PROFILE_ID, _selectedProfile.getProfileId());

            // this will fire a profile change event
            _prefStore.setValue(IPreferences.SRTM_COLORS_SELECTED_PROFILE_KEY, getProfileKeyHashCode());
        }
    }

    /**
     * save state of the pref page
     */
    private void saveState() {

        _booleanEditorApplyOption.store();

        saveSelectedProfile();
        saveViewerState();
    }

    private void saveViewerState() {

        // viewer state
        _columnManager.saveState(_state);
    }

    /**
     * select profile and make it visible,
     */
    private void selectProfileInViewer(final SRTMProfile profile) {

        _profileViewer.setChecked(_selectedProfile, true);

        _profileViewer.getTable().setFocus();

        _profileViewer.setSelection(new StructuredSelection(profile), true);
    }

    @Override
    public void updateColumnHeader(final ColumnDefinition colDef) {
        // TODO Auto-generated method stub

    }
}