gt: 			typeSelection = new Combo(main, SWT.DROP_DOWN | SWT.READ_ONLY);
context: package rocks.inspectit.ui.rcp.wizard.page;
  
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Objects;
  import java.util.Set;
  
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.core.runtime.jobs.Job;
  import org.eclipse.jface.dialogs.IDialogConstants;
  import org.eclipse.jface.dialogs.IMessageProvider;
  import org.eclipse.jface.dialogs.MessageDialog;
  import org.eclipse.jface.dialogs.TitleAreaDialog;
  import org.eclipse.jface.viewers.ArrayContentProvider;
  import org.eclipse.jface.viewers.ISelectionChangedListener;
  import org.eclipse.jface.viewers.SelectionChangedEvent;
  import org.eclipse.jface.viewers.StructuredSelection;
  import org.eclipse.jface.viewers.StyledString;
  import org.eclipse.jface.viewers.TableViewer;
  import org.eclipse.jface.viewers.Viewer;
  import org.eclipse.jface.viewers.ViewerComparator;
  import org.eclipse.jface.window.Window;
  import org.eclipse.jface.wizard.WizardPage;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.custom.SashForm;
  import org.eclipse.swt.custom.ScrolledComposite;
  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.Rectangle;
  import org.eclipse.swt.layout.GridData;
  import org.eclipse.swt.layout.GridLayout;
  import org.eclipse.swt.layout.RowLayout;
  import org.eclipse.swt.widgets.Button;
  import org.eclipse.swt.widgets.Combo;
  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.Label;
  import org.eclipse.swt.widgets.Listener;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.swt.widgets.Table;
  import org.eclipse.swt.widgets.TableColumn;
  import org.eclipse.swt.widgets.Text;
  import org.eclipse.ui.forms.widgets.FormText;
  
  import rocks.inspectit.shared.all.util.ObjectUtils;
  import rocks.inspectit.shared.cs.storage.label.AbstractStorageLabel;
  import rocks.inspectit.shared.cs.storage.label.management.AbstractLabelManagementAction;
  import rocks.inspectit.shared.cs.storage.label.management.impl.AddLabelManagementAction;
  import rocks.inspectit.shared.cs.storage.label.management.impl.RemoveLabelManagementAction;
  import rocks.inspectit.shared.cs.storage.label.type.AbstractCustomStorageLabelType;
  import rocks.inspectit.shared.cs.storage.label.type.AbstractStorageLabelType;
  import rocks.inspectit.shared.cs.storage.label.type.impl.CustomBooleanLabelType;
  import rocks.inspectit.shared.cs.storage.label.type.impl.CustomDateLabelType;
  import rocks.inspectit.shared.cs.storage.label.type.impl.CustomNumberLabelType;
  import rocks.inspectit.shared.cs.storage.label.type.impl.CustomStringLabelType;
  import rocks.inspectit.ui.rcp.InspectIT;
  import rocks.inspectit.ui.rcp.InspectITImages;
  import rocks.inspectit.ui.rcp.editor.viewers.StyledCellIndexLabelProvider;
  import rocks.inspectit.ui.rcp.formatter.ImageFormatter;
  import rocks.inspectit.ui.rcp.formatter.TextFormatter;
  import rocks.inspectit.ui.rcp.repository.CmrRepositoryDefinition;
  import rocks.inspectit.ui.rcp.storage.label.composite.AbstractStorageLabelComposite;
  import rocks.inspectit.ui.rcp.storage.label.composite.impl.BooleanStorageLabelComposite;
  import rocks.inspectit.ui.rcp.storage.label.composite.impl.DateStorageLabelComposite;
  import rocks.inspectit.ui.rcp.storage.label.composite.impl.NumberStorageLabelComposite;
  import rocks.inspectit.ui.rcp.storage.label.composite.impl.StringStorageLabelComposite;
  import rocks.inspectit.ui.rcp.util.SafeExecutor;
  
  /**
   * Manage label page.
   *
   * @author Ivan Senic
   *
   */
  public class ManageLabelWizardPage extends WizardPage {
  
  	/**
  	 * Default message.
  	 */
  	private static final String DEFAULT_MESSAGE = "Add and remove labels that can be used later for labeling storages";
  
  	/**
  	 * Empty style string.
  	 */
  	private static final StyledString EMPTY_STYLED_STRING = new StyledString();
  
  	/**
  	 * Available remote label list.
  	 */
  	private final List<AbstractStorageLabel<?>> labelList = new ArrayList<>();
  
  	/**
  	 * Available remote label type list.
  	 */
  	private final List<AbstractStorageLabelType<?>> labelTypeList = new ArrayList<>();
  
  	/**
  	 * Table viewer for labels.
  	 */
  	private TableViewer labelsTableViewer;
  
  	/**
  	 * Remove label button.
  	 */
  	private Button removeLabels;
  
  	/**
  	 * Add label button.
  	 */
  	private Button createLabel;
  
  	/**
  	 * {@link TableViewer} for label types.
  	 */
  	private TableViewer labelTypeTableViewer;
  
  	/**
  	 * Create label type button.
  	 */
  	private Button createLabelType;
  
  	/**
  	 * Remove label types button.
  	 */
  	private Button removeLabelType;
  
  	/**
  	 * List of labels in storages.
  	 */
  	private final Set<AbstractStorageLabel<?>> labelsInStorages = new HashSet<>();
  
  	/**
  	 * List of actions that need to be executed at the end of wizard.
  	 */
  	private final List<AbstractLabelManagementAction> managementActions = new LinkedList<>();
  
  	/**
  	 * {@link CmrRepositoryDefinition}.
  	 */
  	private final CmrRepositoryDefinition cmrRepositoryDefinition;
  
  	/**
  	 * Default constructor.
  	 *
  	 * @param cmrRepositoryDefinition
  	 *            CMR to manage labels for.
  	 */
  	public ManageLabelWizardPage(CmrRepositoryDefinition cmrRepositoryDefinition) {
  		super("Manage Labels");
  		this.setTitle("Manage Labels");
  		this.setMessage(DEFAULT_MESSAGE);
  		if (null != cmrRepositoryDefinition) {
  			this.setMessage("Label management for repository '" + cmrRepositoryDefinition.getName() + "' (" + cmrRepositoryDefinition.getIp() + ":" + cmrRepositoryDefinition.getPort() + ")");
  		}
  		this.cmrRepositoryDefinition = cmrRepositoryDefinition;
  	}
  
  	/**
  	 * {@inheritDoc}
  	 */
  	@Override
  	public void createControl(Composite parent) {
  		SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
  
  		// label type - upper composite
  		createLabelTypeTable(sashForm);
  		// labels - lower composite
  		createLabelTable(sashForm);
  
  		sashForm.setWeights(new int[] { 1, 1 });
  		setControl(sashForm);
  	}
  
  	/**
  	 * Creates the table for the label types.
  	 *
  	 * @param parent
  	 *            Parent composite.
  	 */
  	private void createLabelTypeTable(Composite parent) {
  		Composite upperComposite = new Composite(parent, SWT.NONE);
  		upperComposite.setLayout(new GridLayout(2, false));
  
  		Label labelTypeInfo = new Label(upperComposite, SWT.NONE);
  		labelTypeInfo.setText("Existing label types");
  		labelTypeInfo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
  
  		Table labelTypeTable = new Table(upperComposite, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL | SWT.FULL_SELECTION);
  		labelTypeTable.setHeaderVisible(true);
  		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2);
  		gd.heightHint = 150;
  		labelTypeTable.setLayoutData(gd);
  
  		TableColumn column = new TableColumn(labelTypeTable, SWT.NONE);
  		column.setMoveable(false);
  		column.setResizable(false);
  		column.setWidth(25);
  
  		column = new TableColumn(labelTypeTable, SWT.NONE);
  		column.setText("Name");
  		column.setMoveable(false);
  		column.setResizable(true);
  		column.setWidth(200);
  
  		column = new TableColumn(labelTypeTable, SWT.NONE);
  		column.setText("Value type");
  		column.setMoveable(false);
  		column.setResizable(true);
  		column.setWidth(100);
  
  		column = new TableColumn(labelTypeTable, SWT.NONE);
  		column.setText("One per storage");
  		column.setMoveable(false);
  		column.setResizable(true);
  		column.setWidth(80);
  
  		labelTypeTableViewer = new TableViewer(labelTypeTable);
  		labelTypeTableViewer.setContentProvider(new ArrayContentProvider());
  		labelTypeTableViewer.setLabelProvider(new StyledCellIndexLabelProvider() {
  			@Override
  			protected StyledString getStyledText(Object element, int index) {
  				if (element instanceof AbstractStorageLabelType) {
  					AbstractStorageLabelType<?> labelType = (AbstractStorageLabelType<?>) element;
  					switch (index) {
  					case 1:
  						return new StyledString(TextFormatter.getLabelName(labelType));
  					case 2:
  						return new StyledString(TextFormatter.getLabelValueType(labelType));
  					case 3:
  						if (labelType.isOnePerStorage()) {
  							return new StyledString("Yes");
  						} else {
  							return new StyledString("No");
  						}
  					default:
  						break;
  					}
  				}
  				return EMPTY_STYLED_STRING;
  			}
  
  			@Override
  			protected Image getColumnImage(Object element, int index) {
  				if ((index == 0) && (element instanceof AbstractStorageLabelType)) {
  					if (isLabelTypeExistsInStorage((AbstractStorageLabelType<?>) element, labelsInStorages)) {
  						return InspectIT.getDefault().getImage(InspectITImages.IMG_STORAGE);
  					}
  				} else if ((index == 1) && (element instanceof AbstractStorageLabelType)) {
  					return ImageFormatter.getImageForLabel((AbstractStorageLabelType<?>) element);
  				}
  				return null;
  			}
  		});
  		labelTypeTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
  			@Override
  			public void selectionChanged(SelectionChangedEvent event) {
  				manageLabelTypeSlection();
  			}
  		});
  		labelTypeTableViewer.setInput(labelTypeList);
  
  		createLabelType = new Button(upperComposite, SWT.PUSH);
  		createLabelType.setText("Add");
  		createLabelType.setToolTipText("Create New Label Type");
  		createLabelType.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
  		createLabelType.addSelectionListener(new SelectionAdapter() {
  			@Override
  			public void widgetSelected(SelectionEvent e) {
  				CreateLabelTypeDialog createDialog = new CreateLabelTypeDialog(getShell());
  				createDialog.open();
  				if (createDialog.getReturnCode() == Window.OK) {
  					AbstractStorageLabelType<?> createdType = createDialog.getCreatedLabelType();
  					AddLabelManagementAction addLabelManagementAction = new AddLabelManagementAction(createdType);
  					managementActions.add(addLabelManagementAction);
  					labelTypeList.add(createdType);
  					labelTypeTableViewer.refresh();
  				}
  			}
  		});
  
  		removeLabelType = new Button(upperComposite, SWT.PUSH);
  		removeLabelType.setText("Remove");
  		removeLabelType.setToolTipText("Remove Label Type");
  		removeLabelType.setEnabled(false);
  		removeLabelType.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
  		removeLabelType.addSelectionListener(new SelectionAdapter() {
  			@Override
  			public void widgetSelected(SelectionEvent e) {
  				AbstractStorageLabelType<?> typeToRemove = (AbstractStorageLabelType<?>) ((StructuredSelection) labelTypeTableViewer.getSelection()).getFirstElement();
  				boolean removeFromStorage = false;
  				if (isLabelTypeExistsInStorage(typeToRemove, labelsInStorages)) {
  					MessageDialog messageDialog = new MessageDialog(getShell(), "Remove Label Type", null, "Should all labels of selected type be removed also from storages where they are used?",
  							MessageDialog.QUESTION, new String[] { "Yes", "No" }, 1);
  					if (messageDialog.open() == 0) {
  						removeFromStorage = true;
  					}
  				}
  				RemoveLabelManagementAction removeLabelManagementAction = new RemoveLabelManagementAction(typeToRemove, removeFromStorage);
  				managementActions.add(removeLabelManagementAction);
  				labelTypeList.remove(typeToRemove);
  				Iterator<AbstractStorageLabel<?>> it = labelList.iterator();
  				while (it.hasNext()) {
  					if (ObjectUtils.equals(typeToRemove, it.next().getStorageLabelType())) {
  						it.remove();
  					}
  				}
  				labelTypeTableViewer.refresh();
  			}
  		});
  
  		Job loadDataJob = new Job("Loading Labels Data") {
  			@Override
  			protected IStatus run(IProgressMonitor monitor) {
  				labelsInStorages.addAll(cmrRepositoryDefinition.getStorageService().getAllLabelsInStorages());
  				labelTypeList.addAll(cmrRepositoryDefinition.getStorageService().getAllLabelTypes());
  				labelList.addAll(cmrRepositoryDefinition.getStorageService().getAllLabels());
  
  				SafeExecutor.asyncExec(new Runnable() {
  					@Override
  					public void run() {
  						labelsTableViewer.refresh();
  						labelTypeTableViewer.refresh();
  					}
  				}, labelsTableViewer.getTable(), labelTypeTableViewer.getTable());
  
  				return Status.OK_STATUS;
  			}
  		};
  		loadDataJob.schedule();
  	}
  
  	/**
  	 * Creates the table for the labels.
  	 *
  	 * @param parent
  	 *            Parent composite.
  	 */
  	private void createLabelTable(Composite parent) {
  		Composite lowerComposite = new Composite(parent, SWT.NONE);
  		lowerComposite.setLayout(new GridLayout(2, false));
  
  		Table table = new Table(lowerComposite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL | SWT.FULL_SELECTION);
  		table.setHeaderVisible(true);
  		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2);
  		gd.heightHint = 150;
  		table.setLayoutData(gd);
  
  		TableColumn column = new TableColumn(table, SWT.NONE);
  		column.setMoveable(false);
  		column.setResizable(false);
  		column.setWidth(25);
  
  		column = new TableColumn(table, SWT.NONE);
  		column.setText("Label");
  		column.setMoveable(false);
  		column.setResizable(true);
  		column.setWidth(200);
  
  		column = new TableColumn(table, SWT.NONE);
  		column.setText("Value");
  		column.setMoveable(false);
  		column.setResizable(true);
  		column.setWidth(100);
  
  		labelsTableViewer = new TableViewer(table);
  		labelsTableViewer.setContentProvider(new ArrayContentProvider());
  		labelsTableViewer.setLabelProvider(new StyledCellIndexLabelProvider() {
  			@Override
  			protected StyledString getStyledText(Object element, int index) {
  				if (element instanceof AbstractStorageLabel) {
  					AbstractStorageLabel<?> label = (AbstractStorageLabel<?>) element;
  					switch (index) {
  					case 1:
  						return new StyledString(TextFormatter.getLabelName(label));
  					case 2:
  						return new StyledString(TextFormatter.getLabelValue(label, false));
  					default:
  						break;
  					}
  				}
  				return EMPTY_STYLED_STRING;
  			}
  
  			@Override
  			protected Image getColumnImage(Object element, int index) {
  				if ((index == 0) && (element instanceof AbstractStorageLabel)) {
  					if (isLabelExistsInStorage((AbstractStorageLabel<?>) element, labelsInStorages)) {
  						return InspectIT.getDefault().getImage(InspectITImages.IMG_STORAGE);
  					}
  				}
  				if ((index == 1) && (element instanceof AbstractStorageLabel)) {
  					return ImageFormatter.getImageForLabel(((AbstractStorageLabel<?>) element).getStorageLabelType());
  				}
  				return null;
  			}
  		});
  		labelsTableViewer.setComparator(new ViewerComparator() {
  			@Override
  			public int compare(Viewer viewer, Object e1, Object e2) {
  				if ((e1 instanceof AbstractStorageLabel) && (e2 instanceof AbstractStorageLabel)) {
  					return ((AbstractStorageLabel<?>) e1).compareTo((AbstractStorageLabel<?>) e2);
  				}
  				return super.compare(viewer, e1, e2);
  			}
  		});
  		labelsTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
  			@Override
  			public void selectionChanged(SelectionChangedEvent event) {
  				if (labelsTableViewer.getSelection().isEmpty()) {
  					removeLabels.setEnabled(false);
  				} else {
  					removeLabels.setEnabled(true);
  				}
  			}
  		});
  
  		createLabel = new Button(lowerComposite, SWT.PUSH);
  		createLabel.setText("Add");
  		createLabel.setToolTipText("Create New Label");
  		createLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
  		createLabel.setEnabled(false);
  		createLabel.addSelectionListener(new SelectionAdapter() {
  			@Override
  			public void widgetSelected(SelectionEvent e) {
  				AbstractStorageLabelType<?> suggestedLabelType = (AbstractStorageLabelType<?>) ((StructuredSelection) labelTypeTableViewer.getSelection()).getFirstElement();
  				CreateLabelDialog createLabelDialog = new CreateLabelDialog(getShell(), labelTypeList, suggestedLabelType);
  				createLabelDialog.open();
  				if (createLabelDialog.getReturnCode() == Window.OK) {
  					AbstractStorageLabel<?> createdLabel = createLabelDialog.getCreatedLabel();
  					List<AbstractStorageLabel<?>> createdList = new ArrayList<>(1);
  					createdList.add(createdLabel);
  					AddLabelManagementAction addLabelManagementAction = new AddLabelManagementAction(createdList);
  					managementActions.add(addLabelManagementAction);
  					labelList.add(createdLabel);
  					manageLabelTypeSlection();
  				}
  			}
  		});
  
  		removeLabels = new Button(lowerComposite, SWT.PUSH);
  		removeLabels.setText("Remove");
  		removeLabels.setToolTipText("Remove Label(s)");
  		removeLabels.setEnabled(false);
  		removeLabels.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
  		removeLabels.addSelectionListener(new SelectionAdapter() {
  			@SuppressWarnings("unchecked")
  			@Override
  			public void widgetSelected(SelectionEvent e) {
  				List<AbstractStorageLabel<?>> labelsToRemove = ((StructuredSelection) labelsTableViewer.getSelection()).toList();
  				boolean inStorage = false;
  				for (AbstractStorageLabel<?> label : labelsToRemove) {
  					if (isLabelExistsInStorage(label, labelsInStorages)) {
  						inStorage = true;
  						break;
  					}
  				}
  
  				boolean removeFromStorage = false;
  				if (inStorage) {
  					MessageDialog messageDialog = new MessageDialog(getShell(), "Remove Label(s)", null, "Should all selected labels be removed also from storages where they are used?",
  							MessageDialog.QUESTION, new String[] { "Yes", "No" }, 1);
  					if (messageDialog.open() == 0) {
  						removeFromStorage = true;
  						labelsInStorages.removeAll(labelsToRemove);
  					}
  				}
  				RemoveLabelManagementAction removeLabelManagementAction = new RemoveLabelManagementAction(labelsToRemove, removeFromStorage);
  				managementActions.add(removeLabelManagementAction);
  				labelList.removeAll(labelsToRemove);
  				manageLabelTypeSlection();
  				labelTypeTableViewer.refresh(true);
  			}
  		});
  
  		FormText storageInfo = new FormText(lowerComposite, SWT.NONE);
  		storageInfo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
  		storageInfo.setImage("storage", InspectIT.getDefault().getImage(InspectITImages.IMG_STORAGE));
  		storageInfo.setText("<form><p>The icon <img href=\"storage\"/> denotes that label type or label is currently used in one or more storages.</p></form>", true, false);
  	}
  
  	/**
  	 * Returns if any storage in collection of storages does contain at least one label that is of
  	 * the given label type.
  	 *
  	 * @param labelType
  	 *            Label type to search for.
  	 * @param labelsInStorages
  	 *            Storages to check.
  	 * @return True if at least one label of given type exists in one of given storages.
  	 */
  	private boolean isLabelTypeExistsInStorage(AbstractStorageLabelType<?> labelType, Set<AbstractStorageLabel<?>> labelsInStorages) {
  		for (AbstractStorageLabel<?> label : labelsInStorages) {
  			if (ObjectUtils.equals(label.getStorageLabelType(), labelType)) {
  				return true;
  			}
  		}
  		return false;
  	}
  
  	/**
  	 * Returns if any storage in collection of storages does contain given label.
  	 *
  	 * @param label
  	 *            Label to search for.
  	 * @param labelsInStorages
  	 *            Storages to check.
  	 * @return True if label exists in one of given storages.
  	 */
  	private boolean isLabelExistsInStorage(AbstractStorageLabel<?> label, Set<AbstractStorageLabel<?>> labelsInStorages) {
  		for (AbstractStorageLabel<?> labelInStorage : labelsInStorages) {
  			if (ObjectUtils.equals(label, labelInStorage)) {
  				return true;
  			}
  		}
  		return false;
  	}
  
  	/**
  	 * Manages the label type selection.
  	 */
  	private void manageLabelTypeSlection() {
  		if (!labelTypeTableViewer.getSelection().isEmpty()) {
  			AbstractStorageLabelType<?> labelType = (AbstractStorageLabelType<?>) ((StructuredSelection) labelTypeTableViewer.getSelection()).getFirstElement();
  			List<AbstractStorageLabel<?>> inputForLabelTable = new ArrayList<>();
  			for (AbstractStorageLabel<?> label : labelList) {
  				if (ObjectUtils.equals(label.getStorageLabelType(), labelType)) {
  					inputForLabelTable.add(label);
  				}
  			}
  			if (labelType.isValueReusable()) {
  				createLabel.setEnabled(true);
  				labelsTableViewer.getTable().setEnabled(true);
  			} else {
  				createLabel.setEnabled(false);
  				labelsTableViewer.getTable().setEnabled(false);
  			}
  			removeLabelType.setEnabled(AbstractCustomStorageLabelType.class.isAssignableFrom(labelType.getClass()));
  			labelsTableViewer.setInput(inputForLabelTable);
  			labelsTableViewer.refresh();
  		} else {
  			removeLabelType.setEnabled(false);
  			createLabel.setEnabled(true);
  			labelsTableViewer.getTable().setEnabled(true);
  			labelsTableViewer.setInput(null);
  			labelsTableViewer.refresh();
  		}
  	}
  
  	/**
  	 * Gets {@link #shouldRefreshStorages}.
  	 *
  	 * @return {@link #shouldRefreshStorages}
  	 */
  	public boolean isShouldRefreshStorages() {
  		return !managementActions.isEmpty();
  	}
  
  	/**
  	 * Gets {@link #managementActions}.
  	 *
  	 * @return {@link #managementActions}
  	 */
  	public List<AbstractLabelManagementAction> getManagementActions() {
  		return managementActions;
  	}
  
  	/**
  	 * Create label type dialog.
  	 *
  	 * @author Ivan Senic
  	 *
  	 */
  	private static class CreateLabelTypeDialog extends TitleAreaDialog {
  
  		/**
  		 * Available type list.
  		 */
  		private final AbstractCustomStorageLabelType<?>[] availableTypes = new AbstractCustomStorageLabelType<?>[] { new CustomBooleanLabelType(), new CustomDateLabelType(),
  				new CustomNumberLabelType(), new CustomStringLabelType() };
  
  		/**
  		 * Reference to the created label type.
  		 */
  		private AbstractStorageLabelType<?> createdLabelType;
  
  		/**
  		 * Keys of the images that can be used in custom labels.
  		 */
  		private final String[] imageKeys;
  
  		/**
  		 * Index of the selected image key.
  		 */
  		private int selectedImageKeyIndex = -1;
  
  		/** Image buttons. */
  		private Button[] imageButtons;
  		/** Ok Button. */
  		private Button okButton;
  		/** The main window. */
  		private Composite main;
  		/** the name. */
  		private Text name;
  		/** Selection of the value type. */
  		private Combo valueTypeSelection;
  		/** yes button. */
  		private Button yesButton;
  		/** no button. */
  		private Button noButton;
  
  		/**
  		 * Default constructor.
  		 *
  		 * @param parentShell
  		 *            Shell
  		 */
  		public CreateLabelTypeDialog(Shell parentShell) {
  			super(parentShell);
  			this.imageKeys = ImageFormatter.LABEL_ICONS;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		protected void configureShell(Shell newShell) {
  			super.configureShell(newShell);
  			newShell.setText("Create Label Type");
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		public void create() {
  			super.create();
  			this.setTitle("Create Label Type");
  			this.setMessage("Define properties for the new label type", IMessageProvider.INFORMATION);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		protected void createButtonsForButtonBar(Composite parent) {
  			createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, true);
  			okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
  			okButton.setEnabled(false);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		protected void buttonPressed(int buttonId) {
  			if (buttonId == IDialogConstants.OK_ID) {
  				createdLabelType = ensureLabelType();
  			}
  			super.buttonPressed(buttonId);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		protected Control createDialogArea(Composite parent) {
  			main = new Composite(parent, SWT.NONE);
  			GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
  			gd.minimumWidth = 350;
  			main.setLayoutData(gd);
  			main.setLayout(new GridLayout(3, false));
  
  			new Label(main, SWT.NONE).setText("Name:");
  			name = new Text(main, SWT.BORDER);
  			name.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
  
  			new Label(main, SWT.NONE).setText("Value type:");
  			valueTypeSelection = new Combo(main, SWT.DROP_DOWN | SWT.READ_ONLY);
  			valueTypeSelection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
  			for (AbstractStorageLabelType<?> labelType : availableTypes) {
  				valueTypeSelection.add(TextFormatter.getLabelValueType(labelType));
  			}
  
  			new Label(main, SWT.NONE).setText("One per storage:");
  			yesButton = new Button(main, SWT.RADIO);
  			yesButton.setText("Yes");
  			yesButton.setSelection(true);
  
  			noButton = new Button(main, SWT.RADIO);
  			noButton.setText("No");
  
  			Label l = new Label(main, SWT.NONE);
  			l.setText("Icon:");
  			l.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
  
  			final ScrolledComposite scrolledComposite = new ScrolledComposite(main, SWT.V_SCROLL | SWT.BORDER);
  			gd = new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1);
  			gd.widthHint = 1;
  			gd.heightHint = 120;
  			scrolledComposite.setLayoutData(gd);
  
  			final Composite iconComposite = new Composite(scrolledComposite, SWT.NONE);
  			iconComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
  
  			// create buttons for selecting images
  			SelectionAdapter buttonListener = new SelectionAdapter() {
  				@Override
  				public void widgetSelected(SelectionEvent e) {
  					for (int i = 0; i < imageButtons.length; i++) {
  						if (Objects.equals(imageButtons[i], e.widget)) {
  							if (selectedImageKeyIndex == i) {
  								// de-selection occurred
  								selectedImageKeyIndex = -1;
  							} else {
  								selectedImageKeyIndex = i;
  							}
  						} else {
  							imageButtons[i].setSelection(false);
  						}
  					}
  				}
  			};
  			imageButtons = new Button[imageKeys.length];
  			for (int i = 0; i < imageKeys.length; i++) {
  				Button button = new Button(iconComposite, SWT.TOGGLE);
  				button.setImage(InspectIT.getDefault().getImage(imageKeys[i]));
  				button.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
  				button.addSelectionListener(buttonListener);
  				imageButtons[i] = button;
  			}
  
  			RowLayout layout = new RowLayout(SWT.HORIZONTAL);
  			layout.wrap = true;
  			layout.fill = true;
  			layout.justify = true;
  			layout.spacing = 7;
  			iconComposite.setLayout(layout);
  			scrolledComposite.setContent(iconComposite);
  			scrolledComposite.setExpandVertical(true);
  			scrolledComposite.setExpandHorizontal(true);
  			scrolledComposite.addControlListener(new ControlAdapter() {
  				@Override
  				public void controlResized(ControlEvent e) {
  					Rectangle r = scrolledComposite.getClientArea();
  					scrolledComposite.setMinSize(iconComposite.computeSize(r.width, SWT.DEFAULT));
  				}
  			});
  
  			final Listener listener = new Listener() {
  				@Override
  				public void handleEvent(Event event) {
  					okButton.setEnabled(isInputValid());
  				}
  
  			};
  			name.addListener(SWT.Modify, listener);
  			valueTypeSelection.addListener(SWT.Selection, listener);
  			yesButton.addListener(SWT.Selection, listener);
  			noButton.addListener(SWT.Selection, listener);
  
  			name.forceFocus();
  			return main;
  		}
  
  		/**
  		 * @return Returns if the input of the dialog is valid.
  		 */
  		private boolean isInputValid() {
  			if (name.getText().trim().isEmpty()) {
  				return false;
  			}
  			if (valueTypeSelection.getSelectionIndex() == -1) {
  				return false;
  			}
  			return true;
  		}
  
  		/**
  		 * Ensures that the label type is correctly created.
  		 *
  		 * @return {@link AbstractStorageLabelType}
  		 */
  		private AbstractStorageLabelType<?> ensureLabelType() {
  			AbstractCustomStorageLabelType<?> labelType = availableTypes[valueTypeSelection.getSelectionIndex()];
  			labelType.setName(name.getText().trim());
  			labelType.setOnePerStorage(yesButton.getSelection());
  			if ((selectedImageKeyIndex >= 0) && (selectedImageKeyIndex < imageKeys.length)) {
  				labelType.setImageKey(imageKeys[selectedImageKeyIndex]);
  			}
  			return labelType;
  		}
  
  		/**
  		 * Gets {@link #createdLabelType}.
  		 *
  		 * @return {@link #createdLabelType}
  		 */
  		public AbstractStorageLabelType<?> getCreatedLabelType() {
  			return createdLabelType;
  		}
  
  	}
  
  	/**
  	 * Create label dialog.
  	 *
  	 * @author Ivan Senic
  	 *
  	 */
  	private static class CreateLabelDialog extends TitleAreaDialog {
  
  		/**
  		 * List of label types that can be created.
  		 */
  		private final List<AbstractStorageLabelType<?>> labelTypes;
  
  		/**
  		 * Suggested label type that will be initially selected.
  		 */
  		private final AbstractStorageLabelType<?> suggestedType;
  
  		/**
  		 * Label type selection Combo.
  		 */
  		private Combo typeSelection;
  
  		/**
  		 * Storage label composite.
  		 */
  		private AbstractStorageLabelComposite storageLabelComposite;
  
  		/**
  		 * OK Button.
  		 */
  		private Button okButton;
  
  		/**
  		 * Main composite.
  		 */
  		private Composite main;
  
  		/**
  		 * Created label reference.
  		 */
  		private AbstractStorageLabel<?> createdLabel;
  
  		/**
  		 * Default constructor.
  		 *
  		 * @param parentShell
  		 *            Shell.
  		 * @param labelTypes
  		 *            List of labels that can be created.
  		 * @param suggestedType
  		 *            Suggested type that will initially be selected in the combo box.
  		 */
  		public CreateLabelDialog(Shell parentShell, List<AbstractStorageLabelType<?>> labelTypes, AbstractStorageLabelType<?> suggestedType) {
  			super(parentShell);
  			this.labelTypes = labelTypes;
  			this.suggestedType = suggestedType;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		protected void configureShell(Shell newShell) {
  			super.configureShell(newShell);
  			newShell.setText("Create Label");
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		public void create() {
  			super.create();
  			this.setTitle("Create Label");
  			this.setMessage("Selected wanted label type and define label value", IMessageProvider.INFORMATION);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		protected void createButtonsForButtonBar(Composite parent) {
  			createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, true);
  			okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
  			okButton.setEnabled(isInputValid());
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		protected void buttonPressed(int buttonId) {
  			if (buttonId == IDialogConstants.OK_ID) {
  				createdLabel = storageLabelComposite.getStorageLabel();
  			}
  			super.buttonPressed(buttonId);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		@Override
  		protected Control createDialogArea(Composite parent) {
  			main = new Composite(parent, SWT.NONE);
  			GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
  			gd.minimumWidth = 350;
  			main.setLayoutData(gd);
  			main.setLayout(new GridLayout(2, false));
  
  			new Label(main, SWT.NONE).setText("Label type:");
  