From 91c1aded321b111ca0e9a9e294d7c010b65d67f1 Mon Sep 17 00:00:00 2001 From: Lorenz Gerber Date: Fri, 18 Jul 2025 17:44:59 +0200 Subject: [PATCH] PCA, descriptive statistics for features Signed-off-by: Lorenz Gerber --- .../META-INF/MANIFEST.MF | 3 +- .../fragment.e4xmi | 2 + .../provider/FeatureStatComparator.java | 135 +++++++++++++++ .../provider/FeatureStatLabelProvider.java | 125 ++++++++++++++ .../pca/ui/parts/FeatureStatTablePart.java | 58 +++++++ .../pca/ui/swt/ExtendedFeatureStatListUI.java | 156 ++++++++++++++++++ .../pca/ui/swt/FeatureStatListUI.java | 149 +++++++++++++++++ 7 files changed, 627 insertions(+), 1 deletion(-) create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/internal/provider/FeatureStatComparator.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/internal/provider/FeatureStatLabelProvider.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/parts/FeatureStatTablePart.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/ExtendedFeatureStatListUI.java create mode 100644 chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/FeatureStatListUI.java diff --git a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/META-INF/MANIFEST.MF b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/META-INF/MANIFEST.MF index ef419afa9d..3016614695 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/META-INF/MANIFEST.MF +++ b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/META-INF/MANIFEST.MF @@ -47,7 +47,8 @@ Require-Bundle: org.eclipse.ui, org.eclipse.help Bundle-RequiredExecutionEnvironment: JavaSE-21 Import-Package: jakarta.annotation;version="2.1.1", - jakarta.inject;version="2.0.1" + jakarta.inject;version="2.0.1", + org.apache.commons.math3.stat.descriptive;version="[3.6.0,4.0.0)" Bundle-ActivationPolicy: lazy Service-Component: OSGI-INF/org.eclipse.chemclipse.xxd.process.supplier.pca.ui.quickstart.FileTileDefinition.xml, OSGI-INF/org.eclipse.chemclipse.xxd.process.supplier.pca.ui.quickstart.FilesLongFormatTileDefinition.xml, diff --git a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/fragment.e4xmi b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/fragment.e4xmi index 247f1de47b..6907274fab 100644 --- a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/fragment.e4xmi +++ b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/fragment.e4xmi @@ -7,6 +7,7 @@ + @@ -19,6 +20,7 @@ + diff --git a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/internal/provider/FeatureStatComparator.java b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/internal/provider/FeatureStatComparator.java new file mode 100644 index 0000000000..621754c77a --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/internal/provider/FeatureStatComparator.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2025 Lablicate GmbH. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lorenz Gerber - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.xxd.process.supplier.pca.ui.internal.provider; + +import java.util.List; + +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; +import org.eclipse.chemclipse.model.statistics.ISampleData; +import org.eclipse.chemclipse.model.statistics.IVariable; +import org.eclipse.chemclipse.support.ui.swt.AbstractRecordTableComparator; +import org.eclipse.chemclipse.support.ui.swt.IRecordTableComparator; +import org.eclipse.chemclipse.xxd.process.supplier.pca.model.Feature; +import org.eclipse.jface.viewers.Viewer; + +public class FeatureStatComparator extends AbstractRecordTableComparator implements IRecordTableComparator { + + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + + int sortOrder = 0; + if(e1 instanceof Feature feature1 && e2 instanceof Feature feature2) { + IVariable variable1 = feature1.getVariable(); + IVariable variable2 = feature2.getVariable(); + DescriptiveStatistics stats = new DescriptiveStatistics(); + List> sampleData1 = feature1.getSampleData(); + List> sampleData2 = feature2.getSampleData(); + // + int columnIndex = getPropertyIndex(); + switch(columnIndex) { + case 0: + try { + double value1 = Double.parseDouble(variable1.getValue()); + double value2 = Double.parseDouble(variable2.getValue()); + sortOrder = Double.compare(value2, value1); + } catch(Exception e) { + sortOrder = variable2.getValue().compareTo(variable1.getValue()); + } + break; + case 1: + sortOrder = variable2.getDescription().compareTo(variable1.getDescription()); + break; + case 2: + for(int i = 0; i < sampleData1.size(); i++) { + stats.addValue(sampleData1.get(i).getData()); + } + Double mean1 = stats.getMean(); + stats = new DescriptiveStatistics(); + for(int i = 0; i < sampleData2.size(); i++) { + stats.addValue(sampleData2.get(i).getData()); + } + Double mean2 = stats.getMean(); + sortOrder = Double.compare(mean2, mean1); + break; + case 3: + for(int i = 0; i < sampleData1.size(); i++) { + stats.addValue(sampleData1.get(i).getData()); + } + Double min1 = stats.getMin(); + stats = new DescriptiveStatistics(); + for(int i = 0; i < sampleData2.size(); i++) { + stats.addValue(sampleData2.get(i).getData()); + } + Double min2 = stats.getMin(); + sortOrder = Double.compare(min2, min1); + break; + case 4: + for(int i = 0; i < sampleData1.size(); i++) { + stats.addValue(sampleData1.get(i).getData()); + } + Double max1 = stats.getMax(); + stats = new DescriptiveStatistics(); + for(int i = 0; i < sampleData2.size(); i++) { + stats.addValue(sampleData2.get(i).getData()); + } + Double max2 = stats.getMax(); + sortOrder = Double.compare(max2, max1); + break; + case 5: + for(int i = 0; i < sampleData1.size(); i++) { + stats.addValue(sampleData1.get(i).getData()); + } + Double rsd1 = stats.getStandardDeviation(); + rsd1 = 100.0 / stats.getSum() * rsd1; + stats = new DescriptiveStatistics(); + for(int i = 0; i < sampleData2.size(); i++) { + stats.addValue(sampleData2.get(i).getData()); + } + Double rsd2 = stats.getStandardDeviation(); + rsd2 = 100.0 / stats.getSum() * rsd2; + sortOrder = Double.compare(rsd2, rsd1); + break; + case 6: + for(int i = 0; i < sampleData1.size(); i++) { + stats.addValue(sampleData1.get(i).getData()); + } + Double skew1 = stats.getSkewness(); + stats = new DescriptiveStatistics(); + for(int i = 0; i < sampleData2.size(); i++) { + stats.addValue(sampleData2.get(i).getData()); + } + Double skew2 = stats.getSkewness(); + sortOrder = Double.compare(skew2, skew1); + break; + case 7: + for(int i = 0; i < sampleData1.size(); i++) { + stats.addValue(sampleData1.get(i).getData()); + } + Double kurt1 = stats.getKurtosis(); + stats = new DescriptiveStatistics(); + for(int i = 0; i < sampleData2.size(); i++) { + stats.addValue(sampleData2.get(i).getData()); + } + Double kurt2 = stats.getKurtosis(); + sortOrder = Double.compare(kurt2, kurt1); + break; + default: + break; + } + } + if(getDirection() == ASCENDING) { + sortOrder = -sortOrder; + } + return sortOrder; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/internal/provider/FeatureStatLabelProvider.java b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/internal/provider/FeatureStatLabelProvider.java new file mode 100644 index 0000000000..5936deabbb --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/internal/provider/FeatureStatLabelProvider.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2025 Lablicate GmbH. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lorenz Gerber - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.xxd.process.supplier.pca.ui.internal.provider; + +import java.text.DecimalFormat; +import java.util.List; + +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; +import org.eclipse.chemclipse.model.statistics.ISampleData; +import org.eclipse.chemclipse.model.statistics.IVariable; +import org.eclipse.chemclipse.support.ui.provider.AbstractChemClipseLabelProvider; +import org.eclipse.chemclipse.xxd.process.supplier.pca.model.Feature; +import org.eclipse.swt.graphics.Image; + +public class FeatureStatLabelProvider extends AbstractChemClipseLabelProvider { + + public static final String VARIABLE = "Variable"; + public static final String NAME = "Name"; + public static final String MEAN = "Mean"; + public static final String MIN = "Min"; + public static final String MAX = "Max"; + public static final String RELATIVESTDDEV = "RSD"; + public static final String SKEWNESS = "Skewness"; + public static final String KURTOSIS = "Excess Kurtosis"; + // + private DecimalFormat decimalFormat = getDecimalFormat(); + // + public static String[] TITLES = {// + VARIABLE, // + NAME, // + MEAN, // + MIN, // + MAX, // + RELATIVESTDDEV, // + SKEWNESS, // + KURTOSIS, // + }; + public static int[] BOUNDS = {// + 50, // + 280, // + 140, // + 140, // + 140, // + 140, // + 140, // + 140 // + }; + + public FeatureStatLabelProvider(String pattern) { + + super(pattern); + } + + @Override + public String getColumnText(Object element, int columnIndex) { + + String text = ""; + if(element instanceof Feature feature) { + IVariable variable = feature.getVariable(); + List> sampleData = feature.getSampleData(); + DescriptiveStatistics stats = new DescriptiveStatistics(); + for(int i = 0; i < sampleData.size(); i++) { + stats.addValue(sampleData.get(i).getData()); + } + double value = 0.0; + // + switch(columnIndex) { + case 0: + text = variable.getValue(); + break; + case 1: + text = variable.getDescription(); + break; + case 2: + value = 0.0; + value = stats.getMean(); + text = Double.isNaN(value) ? "NaN" : decimalFormat.format(value); + break; + case 3: + value = 0.0; + value = stats.getMin(); + text = Double.isNaN(value) ? "NaN" : decimalFormat.format(value); + break; + case 4: + value = 0.0; + value = stats.getMax(); + text = Double.isNaN(value) ? "NaN" : decimalFormat.format(value); + break; + case 5: + value = 0.0; + value = 100.0 / stats.getSum() * stats.getStandardDeviation(); + text = Double.isNaN(value) ? "NaN" : decimalFormat.format(value); + break; + case 6: + value = 0.0; + value = stats.getSkewness(); + text = Double.isNaN(value) ? "NaN" : decimalFormat.format(value); + break; + case 7: + value = 0.0; + value = stats.getKurtosis() - 3.0; + text = Double.isNaN(value) ? "NaN" : decimalFormat.format(value); + default: + break; + } + } + return text; + } + + @Override + public Image getColumnImage(Object element, int columnIndex) { + + return null; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/parts/FeatureStatTablePart.java b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/parts/FeatureStatTablePart.java new file mode 100644 index 0000000000..609fadea61 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/parts/FeatureStatTablePart.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2025 Lablicate GmbH. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lorenz Gerber - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.xxd.process.supplier.pca.ui.parts; + +import java.util.List; + +import org.eclipse.chemclipse.xxd.process.supplier.pca.model.IEvaluation; +import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.swt.ExtendedFeatureStatListUI; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; + +import jakarta.inject.Inject; + +public class FeatureStatTablePart extends AbstractPartPCA { + + @Inject + public FeatureStatTablePart(Composite parent) { + + super(parent); + } + + @Override + protected ExtendedFeatureStatListUI createControl(Composite parent) { + + return new ExtendedFeatureStatListUI(parent, SWT.NONE); + } + + @SuppressWarnings("unchecked") + @Override + protected boolean updateData(List objects, String topic) { + + if(objects.size() == 1) { + if(isUnloadEvent(topic)) { + getControl().setInput(null); + unloadData(); + return false; + } else if(isUpdateSelection(topic)) { + Object object = objects.get(0); + if(object instanceof IEvaluation evaluation) { + getControl().setInput(evaluation); + return true; + } + } + } + // + return false; + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/ExtendedFeatureStatListUI.java b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/ExtendedFeatureStatListUI.java new file mode 100644 index 0000000000..fa28b0ec8e --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/ExtendedFeatureStatListUI.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2025 Lablicate GmbH. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lorenz Gerber - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.xxd.process.supplier.pca.ui.swt; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.chemclipse.model.statistics.ISample; +import org.eclipse.chemclipse.model.statistics.IVariable; +import org.eclipse.chemclipse.support.events.IChemClipseEvents; +import org.eclipse.chemclipse.support.updates.IUpdateListener; +import org.eclipse.chemclipse.swt.ui.notifier.UpdateNotifierUI; +import org.eclipse.chemclipse.ux.extension.ui.model.IDataUpdateListener; +import org.eclipse.chemclipse.ux.extension.ui.support.DataUpdateSupport; +import org.eclipse.chemclipse.ux.extension.ui.swt.IExtendedPartUI; +import org.eclipse.chemclipse.xxd.process.supplier.pca.model.Feature; +import org.eclipse.chemclipse.xxd.process.supplier.pca.model.FeatureDataMatrix; +import org.eclipse.chemclipse.xxd.process.supplier.pca.model.IEvaluation; +import org.eclipse.chemclipse.xxd.process.supplier.pca.model.IResult; +import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.Activator; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Table; + +public class ExtendedFeatureStatListUI extends Composite implements IExtendedPartUI { + + private AtomicReference listControl = new AtomicReference<>(); + // + private IEvaluation evaluation = null; + private FeatureDataMatrix featureDataMatrix = null; + // + private Composite control; + + public ExtendedFeatureStatListUI(Composite parent, int style) { + + super(parent, style); + createControl(); + // + DataUpdateSupport dataUpdateSupport = new DataUpdateSupport(Activator.getDefault().getEventBroker()); + dataUpdateSupport.subscribe(IChemClipseEvents.TOPIC_PCA_UPDATE_RESULT, IChemClipseEvents.EVENT_BROKER_DATA); + dataUpdateSupport.subscribe(IChemClipseEvents.TOPIC_PCA_UPDATE_HIGHLIGHT_LIST_VARIABLE, IChemClipseEvents.EVENT_BROKER_DATA); + dataUpdateSupport.subscribe(IChemClipseEvents.TOPIC_PCA_UPDATE_HIGHLIGHT_PLOT_VARIABLE, IChemClipseEvents.EVENT_BROKER_DATA); + dataUpdateSupport.add(new IDataUpdateListener() { + + @Override + public void update(String topic, List objects) { + + if(evaluation != null) { + if(DataUpdateSupport.isVisible(control)) { + if(IChemClipseEvents.TOPIC_PCA_UPDATE_HIGHLIGHT_PLOT_VARIABLE.equals(topic)) { + if(objects.size() == 1) { + Object object = objects.get(0); + ArrayList features = new ArrayList<>(); + if(object instanceof Object[] values) { + int length = values.length; + for(int i = 0; i < length; i++) { + if(values[i] instanceof Feature feature) { + features.add(feature); + } + } + if(features.size() >= 0) { + List test = evaluation.getSamples().getVariables(); + test.forEach(x -> x.setVisualSelected(false)); + for(Feature feature : features) { + feature.getVariable().setVisualSelected(true); + } + listControl.get().setSelection(new StructuredSelection(features)); + if(features.size() > 0) { + listControl.get().reveal(features.get(0)); + } + } + } + } + } + } + } + } + }); + } + + public void setInput(IEvaluation evaluation) { + + if(doUpdate(evaluation)) { + this.evaluation = evaluation; + updateInput(true); + } + } + + private void updateInput(boolean updateFeatures) { + + if(updateFeatures) { + featureDataMatrix = evaluation != null ? evaluation.getFeatureDataMatrix() : null; + } + updateInput(); + } + + private void createControl() { + + setLayout(new GridLayout(1, true)); + createList(this); + } + + private void createList(Composite parent) { + + FeatureStatListUI featureStatListUI = new FeatureStatListUI(parent, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION | SWT.VIRTUAL); + Table table = featureStatListUI.getTable(); + table.setLayoutData(new GridData(GridData.FILL_BOTH)); + // + featureStatListUI.setUpdateListener(new IUpdateListener() { + + @Override + public void update() { + + UpdateNotifierUI.update(Display.getDefault(), IChemClipseEvents.TOPIC_PCA_UPDATE_FEATURES, evaluation); + } + }); + // + listControl.set(featureStatListUI); + } + + private boolean doUpdate(IEvaluation evaluation) { + + return this.evaluation != evaluation; + } + + private void updateInput() { + + listControl.get().clear(); + // + getDisplay().asyncExec(() -> { + updateWidgets(); + }); + } + + private void updateWidgets() { + + FeatureStatListUI featureStatListUI = listControl.get(); + featureStatListUI.clearColumns(); + featureStatListUI.setInput(featureDataMatrix); + } +} diff --git a/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/FeatureStatListUI.java b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/FeatureStatListUI.java new file mode 100644 index 0000000000..70eb447197 --- /dev/null +++ b/chemclipse/plugins/org.eclipse.chemclipse.xxd.process.supplier.pca.ui/src/org/eclipse/chemclipse/xxd/process/supplier/pca/ui/swt/FeatureStatListUI.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2025 Lablicate GmbH. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Lorenz Gerber - initial API and implementation + *******************************************************************************/ +package org.eclipse.chemclipse.xxd.process.supplier.pca.ui.swt; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.chemclipse.support.ui.provider.ListContentProvider; +import org.eclipse.chemclipse.support.updates.IUpdateListener; +import org.eclipse.chemclipse.xxd.process.supplier.pca.model.FeatureDataMatrix; +import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.internal.provider.FeatureLabelProvider; +import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.internal.provider.FeatureListFilter; +import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.internal.provider.FeatureStatComparator; +import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.internal.provider.FeatureStatLabelProvider; +import org.eclipse.chemclipse.xxd.process.supplier.pca.ui.internal.provider.VisualSelectionFilter; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.TableColumn; + +public class FeatureStatListUI extends org.eclipse.chemclipse.support.ui.swt.ExtendedTableViewer { + + private static final String[] TITLES = FeatureStatLabelProvider.TITLES; + private static final int[] BOUNDS = FeatureStatLabelProvider.BOUNDS; + private final ViewerComparator comparator = new FeatureStatComparator(); + private final FeatureListFilter listFilter = new FeatureListFilter(); + private final VisualSelectionFilter selectFilter = new VisualSelectionFilter(); + private final FeatureStatLabelProvider labelProvider = new FeatureStatLabelProvider("#,##0.####"); + // + private IUpdateListener updateListener = null; + + public FeatureStatListUI(Composite parent, int style) { + + super(parent, style); + setContentProviders(); + createColumnsDefault(); + } + + public void setUpdateListener(IUpdateListener updateListener) { + + this.updateListener = updateListener; + } + + public void updateContent() { + + if(updateListener != null) { + updateListener.update(); + } + } + + public void clear() { + + setInput(null); + } + + public void setInput(FeatureDataMatrix featureDataMatrix) { + + if(featureDataMatrix != null) { + createColumnsSpecific(featureDataMatrix); + super.setInput(featureDataMatrix.getFeatures()); + } else { + super.setInput(Collections.emptyList()); + createColumnsDefault(); + } + } + + private void createColumnsDefault() { + + createColumns(TITLES, BOUNDS, labelProvider, comparator); + } + + private void setContentProviders() { + + setContentProvider(new ListContentProvider()); + setUseHashlookup(true); + setComparator(null); + } + + private void createColumnsSpecific(FeatureDataMatrix featureDataMatrix) { + + /* + * Labels and bounds + */ + String variableName = featureDataMatrix.getVariableName(); + // + List titleList = new ArrayList<>(); + List boundList = new ArrayList<>(); + /* + * Standards Labels + */ + for(int i = 0; i < TITLES.length; i++) { + /* + * Replace the variable name. + */ + String title = TITLES[i]; + if(FeatureLabelProvider.VARIABLE.equals(title)) { + title = variableName; + } + // + titleList.add(title); + boundList.add(BOUNDS[i]); + } + // + String[] titles = titleList.toArray(new String[titleList.size()]); + int size = boundList.size(); + int[] bounds = new int[size]; + for(int i = 0; i < size; i++) { + bounds[i] = boundList.get(i); + } + // + super.setInput(null); + createColumns(titles, bounds, labelProvider, comparator); + } + + private void createColumns(String[] titles, int[] bounds, ITableLabelProvider labelProvider, ViewerComparator comparator) { + + createColumns(titles, bounds); + setColumnStyle(); + setLabelProvider(labelProvider); + setContentProvider(new ListContentProvider()); + setComparator(comparator); + setFilters(listFilter, selectFilter); + } + + private void setColumnStyle() { + + TableColumn[] columns = getTable().getColumns(); + for(TableColumn column : columns) { + column.setAlignment(getStyle(column.getText())); + } + } + + private int getStyle(String label) { + + return SWT.RIGHT; + } +}