blob: 518de9f6da25f14883ac7eca3d2d4934a1a21940 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pierre Allard - initial API and implementation
* Regent L'Archeveque,
* Olivier L. Larouche
*
* SPDX-License-Identifier: EPL-1.0
*******************************************************************************/
package org.eclipse.apogy.common.emf.ui.dialogs;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import javax.measure.converter.UnitConverter;
import javax.measure.unit.AlternateUnit;
import javax.measure.unit.BaseUnit;
import javax.measure.unit.Dimension;
import javax.measure.unit.NonSI;
import javax.measure.unit.ProductUnit;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import javax.measure.unit.UnitFormat;
import org.eclipse.apogy.common.emf.ui.ApogyCommonEMFUIFacade;
import org.eclipse.apogy.common.ui.ApogyCommonUiFacade;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.conversion.Converter;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.databinding.viewers.ViewerProperties;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
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.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.plugin.AbstractUIPlugin;
public class SelectUnitDialog extends Dialog {
private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
private DataBindingContext dataBindingContext;
private final TreeMap<UnitConverter, String> map;
/**
* Data
*/
private final Number value;
private final Unit<?> modelUnit;
private final Unit<?> displayUnit;
private final Unit<?> standardUnit;
private final DecimalFormat currentFormat;
private Unit<?> resultUnit;
private DecimalFormat resultFormat;
/**
* Ui elements
*/
private TreeViewer nativeUnitsTreeViewer;
private Text customText;
private ComboViewer comboNativePrefix;
private CTabItem tbtmNative;
private CTabItem tbtmCustom;
private CTabFolder tabEditorsFolder;
private Text resultLabel;
private Text formatText;
private final static String errorResultMsg = "Unit invalid";
/**
* Constructor
*/
public SelectUnitDialog(Shell parentShell, Number value, DecimalFormat currentFormat, Unit<?> modelUnit,
Unit<?> displayUnit) {
super(parentShell);
setShellStyle(SWT.CLOSE | SWT.MAX | SWT.BORDER | SWT.APPLICATION_MODAL | SWT.RESIZE);
this.currentFormat = currentFormat;
this.resultFormat = currentFormat;
this.value = value;
this.modelUnit = modelUnit;
this.displayUnit = displayUnit;
this.standardUnit = displayUnit.getStandardUnit();
this.map = ApogyCommonEMFUIFacade.INSTANCE.getUnitConverterMap();
}
@Override
protected void configureShell(Shell shell) {
shell.setText("Select units");
super.configureShell(shell);
}
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = new Composite(parent, SWT.None);
composite.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
if (SelectUnitDialog.this.dataBindingContext != null) {
SelectUnitDialog.this.dataBindingContext.dispose();
}
if (SelectUnitDialog.this.toolkit != null) {
SelectUnitDialog.this.toolkit.dispose();
}
}
});
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
composite.setLayout(GridLayoutFactory.fillDefaults().margins(0, 0).numColumns(3).equalWidth(true).create());
/**
* Initial unit
*/
Section sectionInitialUnit = this.toolkit.createSection(composite,
ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED);
this.toolkit.adapt(sectionInitialUnit);
sectionInitialUnit.setText("Initial");
GridData gdData = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);
sectionInitialUnit.setLayoutData(gdData);
sectionInitialUnit.setLayout(new FillLayout());
Composite initialUnitComposite = new Composite(sectionInitialUnit, SWT.None);
initialUnitComposite.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE));
GridLayout initialUnitComposite_gl = new GridLayout(2, false);
initialUnitComposite_gl.marginHeight = 25;
initialUnitComposite.setLayout(initialUnitComposite_gl);
Label unitText = new Label(initialUnitComposite, SWT.WRAP);
unitText.setText(this.currentFormat
.format(this.modelUnit.getConverterTo(this.displayUnit).convert(this.value.doubleValue())) + " "
+ this.displayUnit.toString());
unitText.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 1));
sectionInitialUnit.setClient(initialUnitComposite);
/**
* Unit editors
*/
Composite unitEditorsComposite = new Composite(composite, SWT.None);
unitEditorsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 2));
unitEditorsComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
/**
* Folder
*/
this.tabEditorsFolder = new CTabFolder(unitEditorsComposite, SWT.BORDER);
this.tabEditorsFolder.setLayout(new FillLayout());
UpdateResultStrategy test = new UpdateResultStrategy();
this.tabEditorsFolder.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Unit<?> unit = getUnits();
SelectUnitDialog.this.resultLabel.setText((String) test.convert(unit));
}
});
/**
* Native
*/
this.tbtmNative = new CTabItem(this.tabEditorsFolder, SWT.NONE);
this.tbtmNative.setText("Native");
Composite nativeComposite = new Composite(this.tabEditorsFolder, SWT.None);
nativeComposite.setLayout(new GridLayout(2, false));
nativeComposite.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE));
/** Tree of native units */
this.nativeUnitsTreeViewer = new TreeViewer(nativeComposite, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
Tree tree = this.nativeUnitsTreeViewer.getTree();
tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2));
tree.setHeaderVisible(true);
tree.setLinesVisible(true);
TreeViewerColumn treeViewerUnitColumn = new TreeViewerColumn(this.nativeUnitsTreeViewer, SWT.NONE);
TreeColumn treeclmnUnit = treeViewerUnitColumn.getColumn();
treeclmnUnit.setWidth(100);
treeclmnUnit.setText("Unit");
TreeViewerColumn treeViewerValueColumn = new TreeViewerColumn(this.nativeUnitsTreeViewer, SWT.NONE);
TreeColumn treeclmnValue = treeViewerValueColumn.getColumn();
treeclmnValue.setWidth(100);
treeclmnValue.setText("Value");
this.nativeUnitsTreeViewer.setLabelProvider(new NativeUnitsLabelProvider());
this.nativeUnitsTreeViewer.setContentProvider(new NativeUnitsContentProvider());
this.nativeUnitsTreeViewer.setInput(this.modelUnit);
ApogyCommonUiFacade.INSTANCE.addExpandOnDoubleClick(this.nativeUnitsTreeViewer);
this.nativeUnitsTreeViewer.expandAll();
treeclmnUnit.pack();
treeclmnValue.pack();
if (!this.standardUnit.getDimension().equals(Dimension.NONE)) {
/** Prefix */
Label prefixLabel = new Label(nativeComposite, SWT.WRAP);
prefixLabel.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_TRANSPARENT));
prefixLabel.setText("Prefix");
prefixLabel.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false, 1, 1));
this.comboNativePrefix = new ComboViewer(nativeComposite, SWT.None);
GridData gd_comboNativePrefix = new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1);
this.comboNativePrefix.getCombo().setLayoutData(gd_comboNativePrefix);
this.comboNativePrefix.setLabelProvider(new PrefixesLabelProvider());
this.comboNativePrefix.setContentProvider(new PrefixesContentProvider());
this.comboNativePrefix.setInput(this.map);
}
this.tbtmNative.setControl(nativeComposite);
/**
* Custom unit using the UnitFormat parser
*/
this.tbtmCustom = new CTabItem(this.tabEditorsFolder, SWT.NONE);
this.tbtmCustom.setText("Custom");
/** Display the pattern */
List<Unit<?>> patternUnits = getPattern(this.standardUnit, null);
Composite customComposite = new Composite(this.tabEditorsFolder, SWT.None);
customComposite.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
customComposite.setLayout(new GridLayout(1, false));
if (patternUnits.size() > 0) {
Section compositeUnitSection = this.toolkit.createSection(customComposite,
ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED);
this.toolkit.adapt(compositeUnitSection);
compositeUnitSection.setText("Standard Composition");
compositeUnitSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
compositeUnitSection.setLayout(new GridLayout());
Composite compositeCompositeUnits = new Composite(compositeUnitSection, SWT.None);
compositeCompositeUnits.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, true, 1, 1));
compositeCompositeUnits.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
compositeCompositeUnits.setBackgroundMode(SWT.INHERIT_FORCE);
compositeCompositeUnits.setLayout(new GridLayout(patternUnits.size() * 2, false));
for (Unit<?> patternUnit : patternUnits) {
Composite compositeChooseUnit = new Composite(compositeCompositeUnits, SWT.None);
compositeChooseUnit.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, true, 1, 1));
compositeChooseUnit.setLayout(new GridLayout(2, false));
/** Standard unit for the dimension */
Label standardUnitLabel = new Label(compositeChooseUnit, SWT.None);
standardUnitLabel.setText(patternUnit.toString());
standardUnitLabel.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false, 2, 1));
/**
* Adds a multiplication label if the dimension is not the last one
*/
if (patternUnits.indexOf(patternUnit) != patternUnits.size() - 1) {
Label powerLabel = new Label(compositeCompositeUnits, SWT.None);
powerLabel.setText("*");
powerLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
}
}
compositeUnitSection.setClient(compositeCompositeUnits);
}
/**
* Custom entry
*/
Section customEntrySection = this.toolkit.createSection(customComposite,
ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED);
this.toolkit.adapt(customEntrySection);
customEntrySection.setText("Entry");
customEntrySection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
customEntrySection.setLayout(new FillLayout());
Composite customEntryComposite = new Composite(customEntrySection, SWT.None);
customEntryComposite.setLayout(new GridLayout(2, false));
customEntryComposite.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE));
/** TextBox */
this.customText = new Text(customEntryComposite, SWT.BORDER);
this.customText.setText(this.displayUnit.toString());
this.customText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1));
/** Synthax information button */
Button infoButton = new Button(customEntryComposite, SWT.None);
infoButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true, 1, 1));
ImageDescriptor image = AbstractUIPlugin.imageDescriptorFromPlugin("org.eclipse.jface",
"/icons/full/message_info.png");
infoButton.setImage(image.createImage());
infoButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String message = "Examples of valid entries (all for meters per second squared) are:\n" + " - m*s-2\n"
+ " - m/s²\n" + " - m·s-²\n" + " - m*s**-2\n"
+ " - m^+1 s^-2\n\nPrefixes can only be placed in front of standard units.";
MessageDialog.openInformation(getShell(), "Synthax", message);
}
});
customEntrySection.setClient(customEntryComposite);
/** Available units section */
Section informationsSection = this.toolkit.createSection(customComposite,
ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED);
this.toolkit.adapt(informationsSection);
informationsSection.setText("Available units");
informationsSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
informationsSection.setLayout(new GridLayout());
Composite compositeInformations = new Composite(informationsSection, SWT.None);
compositeInformations.setLayout(new GridLayout(2, true));
compositeInformations.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE));
/** Prefixes */
TreeViewer prefixesTreeViewer = new TreeViewer(compositeInformations, SWT.BORDER);
Tree prefixesTree = prefixesTreeViewer.getTree();
GridData test123 = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
test123.heightHint = 150;
prefixesTree.setLayoutData(test123);
prefixesTree.setHeaderVisible(true);
prefixesTree.setLinesVisible(true);
TreeViewerColumn treeViewerPrefixColumn = new TreeViewerColumn(prefixesTreeViewer, SWT.NONE);
TreeColumn treeclmnPrefix = treeViewerPrefixColumn.getColumn();
treeclmnPrefix.setWidth(50);
treeclmnPrefix.setText("Prefix");
TreeViewerColumn treeViewerPrefixFactorColumn = new TreeViewerColumn(prefixesTreeViewer, SWT.NONE);
TreeColumn treeclmnPrefixFactor = treeViewerPrefixFactorColumn.getColumn();
treeclmnPrefixFactor.setWidth(100);
treeclmnPrefixFactor.setText("Factor");
prefixesTreeViewer.setLabelProvider(new PrefixesTreeLabelProvider());
prefixesTreeViewer.setContentProvider(new PrefixesTreeContentProvider());
prefixesTreeViewer.setInput(this.map);
/** Units */
TreeViewer nativeUnitsTreeViewer = new TreeViewer(compositeInformations, SWT.BORDER | SWT.V_SCROLL);
Tree nativeTree = nativeUnitsTreeViewer.getTree();
GridData gd_nativeUnits = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
gd_nativeUnits.heightHint = 150;
nativeTree.setLayoutData(gd_nativeUnits);
nativeTree.setHeaderVisible(true);
nativeTree.setLinesVisible(true);
ApogyCommonUiFacade.INSTANCE.addExpandOnDoubleClick(nativeUnitsTreeViewer);
TreeViewerColumn treeNativeUnitsColumn = new TreeViewerColumn(nativeUnitsTreeViewer, SWT.NONE);
TreeColumn treeclmnNativeUnits = treeNativeUnitsColumn.getColumn();
treeclmnNativeUnits.setWidth(50);
treeclmnNativeUnits.setText("Units");
nativeUnitsTreeViewer.setLabelProvider(new NativeUnitsListLabelProvider());
nativeUnitsTreeViewer.setContentProvider(new NativeUnitsListContentProvider());
nativeUnitsTreeViewer.setInput("");
informationsSection.setClient(compositeInformations);
this.tbtmCustom.setControl(customComposite);
/**
* Format
*/
CTabItem tbtmFormat = new CTabItem(this.tabEditorsFolder, SWT.NONE);
tbtmFormat.setText("Format");
Composite formatComposite = new Composite(this.tabEditorsFolder, SWT.None);
GridLayout formatComposite_gl = new GridLayout(3, false);
formatComposite_gl.marginHeight = 15;
formatComposite.setLayout(formatComposite_gl);
formatComposite.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE));
formatComposite.setBackgroundMode(SWT.INHERIT_FORCE);
Label formatLabel = new Label(formatComposite, SWT.None);
formatLabel.setText(this.value.getClass().getSimpleName() + " : ");
formatLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
this.formatText = new Text(formatComposite, SWT.BORDER);
this.formatText.setText(this.currentFormat.toPattern());
this.formatText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
this.formatText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
if (verifyFormat()) {
SelectUnitDialog.this.resultFormat = new DecimalFormat(SelectUnitDialog.this.formatText.getText());
} else {
SelectUnitDialog.this.resultFormat = SelectUnitDialog.this.currentFormat;
}
}
});
/** Synthax information button */
Button infoFormatButton = new Button(formatComposite, SWT.None);
infoFormatButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
infoFormatButton.setImage(image.createImage());
infoFormatButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String message = "0\trepresents a digit\n" + "#\trepresents a digit, zero shows as absent\n"
+ ".\trepresents a placeholder for decimal separator\n"
+ ",\trepresents a placeholder for grouping separator\n\n" + "Examples with input 123123.123:\n"
+ "\t- 000000000.000000 : " + new DecimalFormat("000000000.000000").format(123123.123)
+ "\n\t- #########.###### : " + new DecimalFormat("#########.######").format(123123.123)
+ "\n\t- ###,###.### : " + new DecimalFormat("###,###.###").format(123123.123);
MessageDialog.openInformation(getShell(), "Synthax", message);
}
});
tbtmFormat.setControl(formatComposite);
this.tabEditorsFolder.setSelection(this.tbtmNative);
/**
* Preview of the value and the unit.
*/
Section sectionPreview = this.toolkit.createSection(composite,
ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED);
this.toolkit.adapt(sectionPreview);
sectionPreview.setText("Result");
sectionPreview.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
sectionPreview.setLayout(new FillLayout());
Composite previewComposite = new Composite(sectionPreview, SWT.None);
previewComposite.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
previewComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
GridLayout previewComposite_gl = new GridLayout(1, false);
previewComposite_gl.marginHeight = 25;
previewComposite.setLayout(previewComposite_gl);
this.resultLabel = new Text(previewComposite, SWT.WRAP | SWT.CENTER);
this.resultLabel.setText("Preview");
this.resultLabel.setEditable(false);
this.resultLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1));
this.resultLabel.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
SelectUnitDialog.this.resultLabel.requestLayout();
}
});
sectionPreview.setClient(previewComposite);
this.dataBindingContext = initDataBindings();
return composite;
}
private DataBindingContext initDataBindings() {
if (this.dataBindingContext != null) {
this.dataBindingContext.dispose();
}
this.dataBindingContext = new DataBindingContext();
/** Observable for the preview text */
IObservableValue<?> observeResultLabelText = WidgetProperties.text().observe(this.resultLabel);
/** Observables to update the preview */
IObservableValue<?> observeNativeTreeViewerSelection = ViewerProperties.singleSelection()
.observe(this.nativeUnitsTreeViewer);
IObservableValue<?> observeCustomTextText = WidgetProperties.text(SWT.Modify).observe(this.customText);
IObservableValue<?> observeFormatTextText = WidgetProperties.text(SWT.Modify).observe(this.formatText);
/** Bindings */
this.dataBindingContext.bindValue(observeResultLabelText, observeNativeTreeViewerSelection,
new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER), new UpdateResultStrategy());
this.dataBindingContext.bindValue(observeResultLabelText, observeCustomTextText,
new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER), new UpdateResultStrategy());
this.dataBindingContext.bindValue(observeResultLabelText, observeFormatTextText,
new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER), new UpdateResultStrategy());
/** Same binding for the comboViewer */
if (this.comboNativePrefix != null) {
IObservableValue<?> observeComboSelection = ViewerProperties.singleSelection()
.observe(this.comboNativePrefix);
this.dataBindingContext.bindValue(observeResultLabelText, observeComboSelection,
new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER), new UpdateResultStrategy());
}
/** Observable for the format backgroung */
IObservableValue<?> observeFormatTextBackground = WidgetProperties.background().observe(this.formatText);
/** Background binding */
this.dataBindingContext.bindValue(observeFormatTextBackground, observeFormatTextText,
new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER),
new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE)
.setConverter(new Converter(String.class, Color.class) {
@Override
public Object convert(Object fromObject) {
if (fromObject != null) {
return verifyFormat()
? getShell().getDisplay().getSystemColor(SWT.COLOR_TRANSPARENT)
: getShell().getDisplay().getSystemColor(SWT.COLOR_RED);
}
return getShell().getDisplay().getSystemColor(SWT.COLOR_RED);
}
}));
return this.dataBindingContext;
}
/**
* Verifies if the format entered is a valid pattern that can be used to create
* a {@link DecimalFormat}.
*
* @return true if it is valid, false otherwise.
*/
private boolean verifyFormat() {
String text = this.formatText.getText();
/** Can't be empty */
if ("".equals(text)) {
return false;
}
for (int i = 0; i < text.length(); i++) {
char character = text.charAt(i);
/** Can only contain: '0' '.' '#' ',' */
if (character != '0' && character != '.' && character != '#' && character != ',') {
return false;
}
}
/** Tries to create a format */
try {
new DecimalFormat(text);
return true;
} catch (Exception e) {
return false;
}
}
/**
* UpdateResultStrategy to get the unit depending on the option selected. This
* will enable and disable the "ok" button depending if the specified unit by
* the user is compatible with the input unit.
*/
private class UpdateResultStrategy extends UpdateValueStrategy {
public UpdateResultStrategy() {
super(UpdateValueStrategy.POLICY_UPDATE);
setConverter(new Converter(Object.class, String.class) {
@Override
public Object convert(Object fromObject) {
Unit<?> unit = getUnits();
if (SelectUnitDialog.this.getButton(IDialogConstants.OK_ID) != null) {
SelectUnitDialog.this.getButton(IDialogConstants.OK_ID).setEnabled(unit != null);
}
String label = errorResultMsg;
if (unit != null) {
label = unit.toString();
if (SelectUnitDialog.this.value != null) {
label = SelectUnitDialog.this.resultFormat.format(SelectUnitDialog.this.modelUnit
.getConverterTo(unit).convert(SelectUnitDialog.this.value.doubleValue()))
.concat(" " + label);
}
}
return label;
}
});
}
}
/**
* Gets the unit selected in the dialog.
*/
private Unit<?> getUnits() {
/**
* Native units
*/
if (this.tabEditorsFolder.getSelection() == this.tbtmNative) {
/** Get the native unit selected in the tree */
if (this.nativeUnitsTreeViewer.getSelection() != null
&& this.nativeUnitsTreeViewer.getStructuredSelection().getFirstElement() instanceof Unit<?>) {
this.resultUnit = (Unit<?>) this.nativeUnitsTreeViewer.getStructuredSelection().getFirstElement();
} else {
this.resultUnit = SelectUnitDialog.this.displayUnit;
}
/** Get the selected prefix */
if (this.comboNativePrefix != null && this.comboNativePrefix.getStructuredSelection() != null
&& this.comboNativePrefix.getStructuredSelection().getFirstElement() instanceof Entry) {
@SuppressWarnings("unchecked")
Entry<UnitConverter, String> entry = (Entry<UnitConverter, String>) this.comboNativePrefix
.getStructuredSelection().getFirstElement();
this.resultUnit = this.modelUnit.transform(entry.getKey());
}
}
/**
* Custom unit
*/
else if (this.tabEditorsFolder.getSelection() == this.tbtmCustom) {
try {
/** Try to parse the unit */
Object object = UnitFormat.getInstance().parseObject(this.customText.getText());
if (object instanceof Unit<?>) {
this.resultUnit = (Unit<?>) object;
} else {
this.resultUnit = null;
}
} catch (Exception e) {
this.resultUnit = null;
}
}
/**
* Verify if the unit obtained is compatible with the input unit.
*/
if (this.resultUnit != null && this.resultUnit.isCompatible(this.standardUnit)) {
return this.resultUnit;
}
return null;
}
public Unit<?> getResultUnit() {
return this.resultUnit;
}
public DecimalFormat getResultFormat() {
return this.resultFormat;
}
@Override
protected void okPressed() {
super.okPressed();
}
/**
* Gets the unit pattern of a {@link ProductUnit}. This method is similar to
* {@link ProductUnit#getDimension()} but instead return the standard unit of
* the dimension because there are units with the {@link Dimension#NONE} (ex:
* rad, degrees, bit, byte) and this causes errors.
*
* @param unit {@link Unit} to get the pattern.
* @param list {@link List} of {@link Unit}. This is used for the recursive
* nature of the method. To get the pattern of a unit, leave it
* null.
* @return {@link List} of standard {@link Unit} which represents the dimensions
* of the input unit.
*/
private List<Unit<?>> getPattern(Unit<?> unit, List<Unit<?>> list) {
List<Unit<?>> objects = list;
/** Initialization */
if (objects == null) {
objects = new ArrayList<>();
}
/** Get the standard unit */
Unit<?> systemUnit = unit.getStandardUnit();
/**
* ProductUnit
*/
if (systemUnit instanceof ProductUnit<?>) {
ProductUnit<?> productUnit = (ProductUnit<?>) systemUnit;
/** For every dimension */
for (int i = 0; i < productUnit.getUnitCount(); i++) {
Unit<?> unit2 = productUnit.getUnit(i);
if (unit2.getStandardUnit() instanceof ProductUnit<?>) {
objects.addAll(getPattern(unit2.getStandardUnit(), list));
} else {
objects.add(unit2.pow(productUnit.getUnitPow(i)).root(productUnit.getUnitRoot(i)));
}
}
}
/**
* BaseUnit
*/
else if (systemUnit instanceof BaseUnit) {
objects.add(systemUnit);
}
/**
* AlternateUnit
*/
else if (systemUnit instanceof AlternateUnit) {
objects.addAll(getPattern(((AlternateUnit<?>) systemUnit).getParent(), list));
}
return objects;
}
/**
* Gets compatible units in a list.
*
* @param unit The {@link Unit} to match.
* @param list {@link List} of {@link Unit}s to verify.
* @return {@link List} of {@link Unit} compatible with the mentionned unit.
*/
private List<Unit<?>> getCompatibleUnits(Unit<?> unit, Set<Unit<?>> list) {
List<Unit<?>> units = new ArrayList<Unit<?>>();
/**
* If the unit is an empty product unit.
*
* This is used to deal with the case of decibels and percentages.
*/
if (unit instanceof ProductUnit<?> && ((ProductUnit<?>) unit).getUnitCount() < 1) {
return units;
}
Unit<?> stdUnit = unit.getStandardUnit();
for (Unit<?> unit2 : list) {
/** Get the power of the unit if needed */
int power = 1;
if (stdUnit instanceof ProductUnit<?> && ((ProductUnit<?>) stdUnit).getUnitCount() > 0) {
power = ((ProductUnit<?>) stdUnit).getUnitPow(0);
}
/** Adds all the units with the same standard unit */
if (unit2.getStandardUnit().equals(stdUnit) && !units.contains(unit2)) {
units.add(unit2);
}
/**
* Adds all the units with a standard unit that with the right power is the same
* as the units standard unit
*/
else if (unit2.getStandardUnit().pow(power).equals(stdUnit) && !units.contains(unit2.pow(power))) {
units.add(unit2.pow(power));
}
}
return units;
}
/**
* Label provider for the prefixes combo.
*/
private class PrefixesLabelProvider extends ColumnLabelProvider {
@SuppressWarnings("unchecked")
@Override
public String getText(Object element) {
/** Formats the label : symbol (multiplicator) */
if (element instanceof Entry) {
Entry<UnitConverter, String> entry = (Entry<UnitConverter, String>) element;
return entry.getValue() + " (" + entry.getKey().convert(1) + ")";
}
return "";
}
@Override
public Image getImage(Object element) {
return null;
}
}
/**
* Content provider for the prefixes combo.
*/
private class PrefixesContentProvider implements IStructuredContentProvider {
@Override
public Object[] getElements(Object inputElement) {
return SelectUnitDialog.this.map.entrySet().toArray();
}
}
/**
* Label provider for the prefixes combo.
*/
private class PrefixesTreeLabelProvider extends CellLabelProvider {
final private int PREFIX_COLUMN = 0;
final private int FACTOR_COLUMN = 1;
@SuppressWarnings("unchecked")
@Override
public void update(ViewerCell cell) {
if (cell.getElement() instanceof Entry) {
Entry<UnitConverter, String> entry = (Entry<UnitConverter, String>) cell.getElement();
switch (cell.getColumnIndex()) {
case PREFIX_COLUMN:
cell.setText(entry.getValue());
break;
case FACTOR_COLUMN:
cell.setText(Double.toString(entry.getKey().convert(1)));
break;
default:
break;
}
cell.setImage(null);
}
}
}
/**
* Content provider for the prefixes combo.
*/
private class PrefixesTreeContentProvider implements ITreeContentProvider {
@Override
public Object[] getElements(Object inputElement) {
return SelectUnitDialog.this.map.entrySet().toArray();
}
@Override
public Object[] getChildren(Object parentElement) {
return null;
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public boolean hasChildren(Object element) {
return false;
}
}
/**
* Label provider for the native units tree.
*/
private class NativeUnitsLabelProvider extends CellLabelProvider {
final private int UNIT_NAME_COLUMN = 0;
final private int VALUE_COLUMN = 1;
@Override
public void update(ViewerCell cell) {
Object element = cell.getElement();
if (element instanceof String) {
/** SI and NonSI titles */
if (cell.getColumnIndex() == this.UNIT_NAME_COLUMN) {
cell.setText((String) element);
} else {
cell.setText("");
}
} else if (element instanceof Unit) {
Unit<?> unitElement = (Unit<?>) element;
switch (cell.getColumnIndex()) {
case UNIT_NAME_COLUMN:
/** Unit name */
if (unitElement.toString() != null) {
cell.setText(unitElement.toString());
}
break;
case VALUE_COLUMN:
/** Converted value */
UnitConverter converter = SelectUnitDialog.this.modelUnit.getConverterTo(unitElement);
if (converter != null && SelectUnitDialog.this.value != null) {
cell.setText(Double.toString(converter.convert(SelectUnitDialog.this.value.doubleValue())));
}
break;
default:
break;
}
}
}
}
/**
* Content provider for the native units tree.
*/
private class NativeUnitsContentProvider implements ITreeContentProvider {
final private static String SI_STRING = "SI";
final private static String NON_SI_STRING = "Non-SI";
final private static String EMPTY = "No unit available";
@Override
public Object[] getElements(Object inputElement) {
return new Object[] { SI_STRING, NON_SI_STRING };
}
@Override
public Object[] getChildren(Object parentElement) {
List<Unit<?>> SIunits = getCompatibleUnits(SelectUnitDialog.this.standardUnit, SI.getInstance().getUnits());
List<Unit<?>> NonSIunits = getCompatibleUnits(SelectUnitDialog.this.standardUnit,
NonSI.getInstance().getUnits());
/** If no unit is found, add the unit to the NonSI */
if (SIunits.isEmpty() && NonSIunits.isEmpty()) {
Unit<?> stdUnit = SelectUnitDialog.this.modelUnit.getStandardUnit();
if (SI.getInstance().getUnits().contains(stdUnit)) {
SIunits.add(stdUnit);
}
if (!SIunits.contains(SelectUnitDialog.this.modelUnit)) {
NonSIunits.add(SelectUnitDialog.this.modelUnit);
}
if (!SIunits.contains(SelectUnitDialog.this.displayUnit)
&& !NonSIunits.contains(SelectUnitDialog.this.displayUnit)) {
NonSIunits.add(SelectUnitDialog.this.displayUnit);
}
}
return SI_STRING.equals(parentElement) ? SIunits.toArray() : NonSIunits.toArray();
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public boolean hasChildren(Object element) {
return element instanceof String ? !((String) element).equals(EMPTY) : false;
}
}
/**
* Label provider for the native units list tree.
*/
private class NativeUnitsListLabelProvider extends CellLabelProvider {
@Override
public void update(ViewerCell cell) {
cell.setText(cell.getElement().toString());
}
}
/**
* Content provider for the native units list tree.
*/
private class NativeUnitsListContentProvider implements ITreeContentProvider {
@Override
public Object[] getElements(Object inputElement) {
ArrayList<Unit<?>> siUnits = new ArrayList<>();
/** Adds SI units with the same standard unit */
for (Unit<?> unit : SI.getInstance().getUnits()) {
if (!siUnits.contains(unit.getStandardUnit())) {
siUnits.add(unit.getStandardUnit());
}
}
/** Adds NonSI units with the same standad unit */
for (Unit<?> unit : NonSI.getInstance().getUnits()) {
if (!siUnits.contains(unit.getStandardUnit())) {
if (!unit.getStandardUnit().toString().equals("")) {
siUnits.add(unit.getStandardUnit());
} else {
siUnits.add(unit);
}
}
}
return siUnits.toArray();
}
@Override
public Object[] getChildren(Object parentElement) {
if (((Unit<?>) parentElement).getStandardUnit() == parentElement) {
Set<Unit<?>> units = new HashSet<>(SI.getInstance().getUnits());
units.addAll(NonSI.getInstance().getUnits());
List<Unit<?>> unitsList = getCompatibleUnits((Unit<?>) parentElement, units);
unitsList.remove(parentElement);
return unitsList.toArray();
}
return null;
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public boolean hasChildren(Object element) {
Object[] children = getChildren(element);
return children != null && children.length > 0;
}
}
}