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