/*
* Copyright (c) 2012 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* HUMBOLDT EU Integrated Project #030962
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.ui.views.data.internal.compare;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeColumnViewerLabelProvider;
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.TreeEditor;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
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.Layout;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import eu.esdihumboldt.hale.common.instance.model.Instance;
import eu.esdihumboldt.hale.common.schema.SchemaSpaceID;
import eu.esdihumboldt.hale.common.schema.model.TypeDefinition;
import eu.esdihumboldt.hale.ui.common.definition.viewer.DefinitionComparator;
import eu.esdihumboldt.hale.ui.views.data.InstanceViewer;
import eu.esdihumboldt.hale.ui.views.data.internal.MetadataActionProvider;
import eu.esdihumboldt.hale.ui.views.data.internal.SimpleInstanceSelectionProvider;
import eu.esdihumboldt.util.Pair;
/**
* Tree viewer for {@link Instance}s of a common type, based on the
* corresponding {@link TypeDefinition}
*
* @author Simon Templer
* @partner 01 / Fraunhofer Institute for Computer Graphics Research
*/
public class DefinitionInstanceTreeViewer implements InstanceViewer {
// private static ALogger _log =
// ALoggerFactory.getLogger(DefinitionInstanceTreeViewer.class);
private TreeViewer treeViewer;
private Composite main;
private TreeEditor editor;
private MetadataActionProvider maep;
private final SimpleInstanceSelectionProvider selectionProvider = new SimpleInstanceSelectionProvider();
private final Map<Integer, DefinitionInstanceLabelProvider> labelProviders = new HashMap<Integer, DefinitionInstanceLabelProvider>();
/**
* @see InstanceViewer#createControls(Composite, SchemaSpaceID)
*/
@Override
public void createControls(final Composite parent, SchemaSpaceID schemaSpace) {
main = new Composite(parent, SWT.NONE);
main.setLayout(new TreeColumnLayout());
treeViewer = new TreeViewer(main, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
treeViewer.setContentProvider(new TypeMetaPairContentProvider(treeViewer, schemaSpace));
treeViewer.setLabelProvider(new DefinitionMetaCompareLabelProvider(treeViewer));
// Add an editor for selecting specific paths.
editor = new TreeEditor(treeViewer.getTree());
editor.horizontalAlignment = SWT.RIGHT;
treeViewer.getTree().addMouseMoveListener(new MouseMoveListener() {
@Override
public void mouseMove(MouseEvent e) {
final ViewerCell cell = treeViewer.getCell(new Point(e.x, e.y));
// Selected cell changed?
if (cell == null || editor.getItem() != cell.getItem()
|| editor.getColumn() != cell.getColumnIndex()) {
// Clean up any previous editor control
Control oldEditor = editor.getEditor();
if (oldEditor != null) {
oldEditor.dispose();
editor.setEditor(null, null, 0);
}
}
// No valid selected cell
if (cell == null || cell.getColumnIndex() == 0) {
return;
}
// cell didn't change
if ((editor.getItem() == cell.getItem() && editor.getColumn() == cell
.getColumnIndex())) {
return;
}
Composite editorControl = new Composite(treeViewer.getTree(), SWT.NONE);
GridLayoutFactory.fillDefaults().margins(0, 0).spacing(0, 0).numColumns(2)
.applyTo(editorControl);
boolean hideCopy = false;
// multi value selector
// Quote the format first. Pattern.quote does the same, except,
// that it checks the input for \Es.
// Since we know that there will be no \Es in this case
// do it ourselves to be safe from changes to Pattern.quote.
String pattern = "\\Q" + DefinitionInstanceLabelProvider.MULTIPLE_VALUE_FORMAT
+ "\\E$";
pattern = pattern.replace("{0}", "\\E(\\d+)\\Q").replace("{1}", "\\E(\\d+)\\Q");
Matcher m = Pattern.compile(pattern).matcher(cell.getText());
if (m.find()) {
// multi value element
int current = Integer.parseInt(m.group(1));
int total = Integer.parseInt(m.group(2));
// Create the selection control.
ComboViewer combo = new ComboViewer(editorControl);
Integer[] values = new Integer[total];
for (int i = 1; i <= total; i++)
values[i - 1] = i;
combo.setContentProvider(ArrayContentProvider.getInstance());
combo.setInput(values);
combo.setSelection(new StructuredSelection(current));
combo.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
if (event.getSelection() instanceof IStructuredSelection) {
// Update label provider and refresh viewer.
labelProviders.get(cell.getColumnIndex()).selectPath(
cell.getViewerRow().getTreePath(),
(Integer) (((IStructuredSelection) event.getSelection())
.getFirstElement()));
treeViewer.refresh(cell.getElement(), true);
}
}
});
}
else {
/*
* only one value - so we can safely determine if the copy
* button should be shown
*/
Object value = labelProviders.get(cell.getColumnIndex())
.findInstanceEntry(cell.getViewerRow().getTreePath()).getValue();
if (value instanceof Instance) {
value = ((Instance) value).getValue();
}
hideCopy = value == null || value.toString().isEmpty();
}
// copy button
if (!hideCopy) {
Button button = new Button(editorControl, SWT.PUSH | SWT.FLAT);
button.setImage(PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_TOOL_COPY));
button.setToolTipText("Copy string value");
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// determine text value
Object value = labelProviders.get(cell.getColumnIndex())
.findInstanceEntry(cell.getViewerRow().getTreePath())
.getValue();
if (value instanceof Instance) {
value = ((Instance) value).getValue();
}
if (value != null) {
final String textValue = value.toString();
if (!textValue.isEmpty()) { // empty string is
// invalid
// copy content to clipboard
Clipboard clipBoard = new Clipboard(Display.getCurrent());
clipBoard.setContents(new Object[] { textValue },
new Transfer[] { TextTransfer.getInstance() });
clipBoard.dispose();
}
}
}
});
}
// calculate editor size
Point size = editorControl.computeSize(SWT.DEFAULT, SWT.DEFAULT);
editor.minimumHeight = size.y;
editor.minimumWidth = size.x;
editor.setEditor(editorControl, (TreeItem) cell.getItem(), cell.getColumnIndex());
}
});
maep = new MetadataCompareActionProvider(treeViewer);
maep.setup();
treeViewer.setComparator(new DefinitionComparator());
treeViewer.getTree().setHeaderVisible(true);
treeViewer.getTree().setLinesVisible(true);
ColumnViewerToolTipSupport.enableFor(treeViewer);
setInput(null, null);
}
/**
* @see InstanceViewer#setInput(TypeDefinition, Iterable)
*/
@Override
public void setInput(TypeDefinition type, Iterable<Instance> instances) {
// remove old columns
TreeColumn[] columns = treeViewer.getTree().getColumns();
if (columns != null) {
for (TreeColumn column : columns) {
column.dispose();
}
labelProviders.clear();
}
// create row defs for metadata
// if (features != null) {
// boolean displayLineage = false;
// int lineageLength = 0;
// int featuresSize = 0;
// for (Feature f : features) {
// featuresSize++;
// Lineage l = (Lineage) f.getUserData().get("METADATA_LINEAGE"); //$NON-NLS-1$
// if (l != null && l.getProcessSteps().size() > 0) {
// displayLineage = true;
// if (lineageLength < l.getProcessSteps().size()) {
// lineageLength = l.getProcessSteps().size();
// }
// }
// }
//
// if (displayLineage) {
// Object[][] processStepsText = new Object[lineageLength][featuresSize + 1];
// int featureIndex = 0;
// for (Feature f : features) {
// Lineage l = (Lineage) f.getUserData().get("METADATA_LINEAGE"); //$NON-NLS-1$
// if (l != null && l.getProcessSteps().size() > 0) {
// int psIndex = 0;
// for (ProcessStep ps : l.getProcessSteps()) {
// processStepsText[psIndex][featureIndex + 1] = ps.getDescription().toString();
// psIndex++;
// }
// }
// featureIndex++;
// }
//
// DefaultTreeNode lineage = new DefaultTreeNode(Messages.DefinitionFeatureTreeViewer_5); //$NON-NLS-1$
// metadata.addChild(lineage);
// for (int i = 0; i < lineageLength; i++) {
// processStepsText[i][0] = Messages.DefinitionFeatureTreeViewer_6 + (i + 1); //$NON-NLS-1$
// DefaultTreeNode processStep = new DefaultTreeNode(processStepsText[i]);
// lineage.addChild(processStep);
// }
// }
// set input
if (type != null) {
// pass metadatas to the treeviewer, if instances contain metadatas
Set<String> completeMetaNames = new HashSet<String>();
for (Instance inst : instances) {
for (String name : inst.getMetaDataNames()) {
completeMetaNames.add(name);
}
}
Pair<TypeDefinition, Set<String>> pair = new Pair<TypeDefinition, Set<String>>(type,
completeMetaNames);
treeViewer.setInput(pair);
}
else
treeViewer.setInput(Collections.emptySet());
Layout layout = treeViewer.getTree().getParent().getLayout();
// add type column
if (type != null) {
TreeViewerColumn column = new TreeViewerColumn(treeViewer, SWT.LEFT);
column.getColumn().setText(type.getDisplayName());
column.setLabelProvider(new TreeColumnViewerLabelProvider(
new DefinitionMetaCompareLabelProvider(treeViewer)));
if (layout instanceof TreeColumnLayout) {
((TreeColumnLayout) layout).setColumnData(column.getColumn(), new ColumnWeightData(
1));
}
}
// add columns for features
int index = 1;
if (instances != null) {
// // sort features
// List<Feature> sortedFeatures = new ArrayList<Feature>();
// for (Feature f : features) {
// sortedFeatures.add(f);
// }
// Collections.sort(sortedFeatures, new Comparator<Feature>() {
//
// @Override
// public int compare(Feature o1, Feature o2) {
// FeatureId id1 = FeatureBuilder.getSourceID(o1);
// if (id1 == null) {
// id1 = o1.getIdentifier();
// }
//
// FeatureId id2 = FeatureBuilder.getSourceID(o2);
// if (id2 == null) {
// id2 = o2.getIdentifier();
// }
//
// return id1.getID().compareTo(id2.getID());
// }
//
// });
List<Instance> insts = new ArrayList<Instance>();
for (Instance instance : instances) { // sortedFeatures) {
final TreeViewerColumn column = new TreeViewerColumn(treeViewer, SWT.LEFT);
// FeatureId id = FeatureBuilder.getSourceID(feature);
// if (id == null) {
// id = feature.getIdentifier();
// }
// column.getColumn().setText(id.toString());
column.getColumn().setText(String.valueOf(index)); // XXX
// identifier?
DefinitionInstanceLabelProvider labelProvider = new DefinitionInstanceLabelProvider(
instance);
labelProviders.put(index, labelProvider);
column.setLabelProvider(labelProvider);
if (layout instanceof TreeColumnLayout) {
((TreeColumnLayout) layout).setColumnData(column.getColumn(),
new ColumnWeightData(1));
}
// add tool tip
// new ColumnBrowserTip(treeViewer, 400, 300, true, index, null);
insts.add(instance);
index++;
}
((MetadataCompareActionProvider) maep).setInput(insts, labelProviders);
}
treeViewer.refresh();
treeViewer.getTree().getParent().layout(true, true);
selectionProvider.updateSelection(instances);
// auto-expand attributes/metadata
treeViewer.expandToLevel(2);
}
/**
* @see InstanceViewer#getViewer()
*/
@Override
public TreeViewer getViewer() {
return treeViewer;
}
/**
* @see InstanceViewer#getControl()
*/
@Override
public Control getControl() {
return main;
}
/**
* @see InstanceViewer#getInstanceSelectionProvider()
*/
@Override
public ISelectionProvider getInstanceSelectionProvider() {
return selectionProvider;
}
}