/* * Copyright 2016 Diamond Light Source Ltd. * * 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 */ package uk.ac.diamond.scisoft.xpdf.views; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ComboBoxCellEditor; import org.eclipse.jface.viewers.ComboBoxViewerCellEditor; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; /** * Grouped table to edit the atoms in a unit cell * @author Timothy Spain, timothy.spain@diamond.ac.uk * */ class UnitCellGroupedTable { private static List<XPDFAtom> defaultAtoms; private List<XPDFAtom> atoms; private XPDFSpaceGroup theGroup; private XPDFGroupedTable groupedTable; private boolean inhibitAddingAtom; /** * Constructor for the table. * @param parent * Composite into which the table will be placed. Does not * need a {@link TableColumnLayout}. * @param style * Style bits to apply to the table. */ public UnitCellGroupedTable(Composite parent, int style) { if (defaultAtoms == null) { defaultAtoms = new ArrayList<XPDFAtom>(); // All phases are ferrous titanate defaultAtoms.add(new XPDFAtom("Fe1", 26, 1.0, new double[] {0.333, 0.333, 0.333}, "c")); // defaultAtoms.add(new XPDFAtom("Fe2", 26, 1.0, new double[] {0.667, 0.667, 0.667})); defaultAtoms.add(new XPDFAtom("Ti1", 22, 1.0, new double[] {0.167, 0.167, 0.167}, "c")); // defaultAtoms.add(new XPDFAtom("Ti2", 22, 1.0, new double[] {0.833, 0.833, 0.833})); defaultAtoms.add(new XPDFAtom("O1", 8, 1.0, new double[] {0.583, 0.917, 0.250}, "f")); // defaultAtoms.add(new XPDFAtom("O2", 8, 1.0, new double[] {0.917, 0.250, 0.583})); // defaultAtoms.add(new XPDFAtom("O3", 8, 1.0, new double[] {0.250, 0.583, 0.917})); // defaultAtoms.add(new XPDFAtom("O4", 8, 1.0, new double[] {-0.583, -0.917, -0.250})); // defaultAtoms.add(new XPDFAtom("O5", 8, 1.0, new double[] {-0.917, -0.250, -0.583})); // defaultAtoms.add(new XPDFAtom("O6", 8, 1.0, new double[] {-0.250, -0.583, -0.917})); } groupedTable = new XPDFGroupedTable(parent, SWT.NONE); createColumns(); groupedTable.setContentProvider(new AtomContentProvider()); inhibitAddingAtom = false; groupedTable.addMouseListener(new MouseListener() { @Override public void mouseDoubleClick(MouseEvent e) { } @Override public void mouseDown(MouseEvent e) { } @Override public void mouseUp(MouseEvent e) { if (e.button == 1) { if (!inhibitAddingAtom) { atoms.add(new XPDFAtom()); groupedTable.refresh(); } } inhibitAddingAtom = false; } }); groupedTable.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { // If there is a selection event, inhibit the mouse up from adding an atom inhibitAddingAtom = true; } @Override public void widgetDefaultSelected(SelectionEvent e) { } }); } /** * Sets the layout data to apply to the table as a whole * @param layout * the layout to be applied */ public void setLayoutData(Object layout) { groupedTable.setLayoutData(layout); } /** * Sets the data source of the table. * @param atoms * A Map between labels and atoms */ public void setInput(List<XPDFAtom> atoms, XPDFSpaceGroup group) { this.atoms = atoms; this.theGroup = group; groupedTable.setInput(this.atoms); } /** * Refreshes the internal table. */ public void refresh() { groupedTable.refresh(); } /** * Returns the Map of labels to atoms * @return * the map of labels to atoms in this unit cell. */ public List<XPDFAtom> getAtoms() { return atoms; } private void createColumns() { List<String> groupNames = new ArrayList<String>(); List<ColumnInterface> columnInterfaces; List<List<ColumnInterface>> groupedColumnInterfaces = new ArrayList<List<ColumnInterface>>(); groupNames.add("Atom"); columnInterfaces = new ArrayList<ColumnInterface>(); columnInterfaces.add(new ElementColumnInterface()); columnInterfaces.add(new LabelColumnInterface()); groupedColumnInterfaces.add(columnInterfaces); groupNames.add("Position"); columnInterfaces = new ArrayList<ColumnInterface>(); columnInterfaces.add(new PositionColumnInterface(0)); columnInterfaces.add(new PositionColumnInterface(1)); columnInterfaces.add(new PositionColumnInterface(2)); groupedColumnInterfaces.add(columnInterfaces); groupNames.add("Site"); columnInterfaces = new ArrayList<ColumnInterface>(); columnInterfaces.add(new WyckoffColumnInterface()); columnInterfaces.add(new MultiplicityColumnInterface()); groupedColumnInterfaces.add(columnInterfaces); groupNames.add("‍"); columnInterfaces = new ArrayList<ColumnInterface>(); columnInterfaces.add(new OccupancyColumnInterface()); columnInterfaces.add(new adpColumnInterface()); groupedColumnInterfaces.add(columnInterfaces); for (int iGroup = 0; iGroup < groupNames.size(); iGroup++) { groupedTable.createColumnGroup(groupNames.get(iGroup), iGroup == groupNames.size()-1); for (int iColumn = 0; iColumn < groupedColumnInterfaces.get(iGroup).size(); iColumn++) { ColumnInterface colI = groupedColumnInterfaces.get(iGroup).get(iColumn); TableViewerColumn col = groupedTable.addColumn(groupNames.get(iGroup), SWT.NONE); col.getColumn().setText(colI.getName()); groupedTable.setColumnWidth(col, colI.getWeight()); col.setLabelProvider(colI.getLabelProvider()); groupedTable.setColumnEditingSupport(col, colI); // Sorting on column header button selection. See PhaseGroupedTable for reference // if (colI.getSelectionAdapter(this, col) != null) col.getColumn().addSelectionListener(colI.getSelectionAdapter(this, col)); } } } private class AtomContentProvider implements IStructuredContentProvider { @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public Object[] getElements(Object inputElement) { return atoms.toArray(new XPDFAtom[atoms.size()]); } } private interface ColumnInterface extends EditingSupportFactory { // public SelectionAdapter getSelectionAdapter(final UnitCellDialog uCD, final TableViewerColumn col); public ColumnLabelProvider getLabelProvider(); public String getName(); public int getWeight(); public boolean presentAsUneditable(Object element); } private static class DummyColumnInterface implements ColumnInterface { @Override public EditingSupport get(ColumnViewer v) { return new DummyEditingSupport(v); } // @Override // public SelectionAdapter getSelectionAdapter(UnitCellDialog uCD, // TableViewerColumn col) { // return DummySelectionAdapter.get(uCD, col); // } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return "This space left intentionally blank"; } }; } @Override public String getName() { return "Column"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return false; } } private static class DummyEditingSupport extends EditingSupport { DummyEditingSupport(ColumnViewer v) { super(v); } @Override protected CellEditor getCellEditor(Object element) { return null; } @Override protected boolean canEdit(Object element) { return false; } @Override protected Object getValue(Object element) { return null; } @Override protected void setValue(Object element, Object value) { } } // private static class DummyLabelProvider extends ColumnLabelProvider { // String text; // public DummyLabelProvider(String text) { // this.text = text; // } // @Override // public String getText(Object element) { // return text; // } // } private class ElementColumnInterface implements ColumnInterface { private final List<String> elementSymbol = Arrays.asList( new String[] { "?", "H","He","Li","Be","B","C","N","O","F","Ne", "Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca", "Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu","Zn", "Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y","Zr", "Nb","Mo","Tc","Ru","Rh","Pd","Ag","Cd","In","Sn", "Sb","Te","I","Xe","Cs","Ba","La","Ce","Pr","Nd", "Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb", "Lu","Hf","Ta","W","Re","Os","Ir","Pt","Au","Hg", "Tl","Pb","Bi","Po","At","Rn","Fr","Ra","Ac","Th", "Pa","U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm"} ); private static final int elementOffset = 1; @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v) { @Override protected CellEditor getCellEditor(Object element) { Table theTable = ((TableViewer) v).getTable(); String[] elementStrings = elementSymbol.subList(elementOffset, elementSymbol.size()).toArray(new String[elementSymbol.size()-1]); ComboBoxViewerCellEditor theEditor = new ElementComboViewerEditor(theTable); theEditor.setInput(elementStrings); return theEditor; // return new ComboBoxCellEditor(theTable, elementStrings); } @Override protected boolean canEdit(Object element) { return true; } @Override protected Object getValue(Object element) { int atomicNumber; if (element instanceof XPDFAtom) atomicNumber = ((XPDFAtom) element).getAtomicNumber(); else atomicNumber = elementOffset; return atomicNumber - elementOffset; } @Override protected void setValue(Object element, Object value) { if (value instanceof Integer) { int atomicNumber = (Integer) value; atomicNumber += elementOffset; if (element instanceof XPDFAtom) ((XPDFAtom) element).setAtomicNumber(atomicNumber); } v.refresh(element); } }; } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { int atomicNumber = 0; if (element instanceof XPDFAtom) atomicNumber = ((XPDFAtom) element).getAtomicNumber(); return elementSymbol.get(atomicNumber); } }; } @Override public String getName() { return "Element"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return false; } } private class LabelColumnInterface implements ColumnInterface { @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v) { @Override protected CellEditor getCellEditor(Object element) { return new TextCellEditor(((TableViewer) v).getTable()); } @Override protected boolean canEdit(Object element) { return true; } @Override protected Object getValue(Object element) { return ((XPDFAtom) element).getLabel(); } @Override protected void setValue(Object element, Object value) { if (element instanceof XPDFAtom) ((XPDFAtom) element).setLabel(value.toString()); v.refresh(element); } }; } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return (element instanceof XPDFAtom) ? ((XPDFAtom) element).getLabel() : ""; } }; } @Override public String getName() { return "Label"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return false; } } private static class PositionColumnInterface implements ColumnInterface { static final String[] axisNames = {"x", "y", "z"}; private int axisIndex; public PositionColumnInterface(int axisIndex) { this.axisIndex = axisIndex; } @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v) { @Override protected CellEditor getCellEditor(Object element) { return new TextCellEditor(((TableViewer) v).getTable()); } @Override protected boolean canEdit(Object element) { return true; } @Override protected Object getValue(Object element) { return (element instanceof XPDFAtom) ? Double.toString(((XPDFAtom) element).getPosition()[axisIndex]) : null; } @Override protected void setValue(Object element, Object value) { if (element instanceof XPDFAtom && value instanceof String) { String valueString = (String) value; double coordinate = 0.0; try { coordinate = Double.parseDouble(valueString); } catch (NumberFormatException nFE) { ; } ((XPDFAtom) element).setPosition(axisIndex, coordinate); v.refresh(); } } }; } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return (element instanceof XPDFAtom) ? Double.toString(((XPDFAtom) element).getPosition()[axisIndex]) : ""; } }; } @Override public String getName() { return axisNames[axisIndex]; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return false; } } private class WyckoffColumnInterface implements ColumnInterface { @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v) { @Override protected CellEditor getCellEditor(Object element) { Table theTable = ((TableViewer) v).getTable(); String[] WyckoffStrings = Arrays.copyOfRange(XPDFSpaceGroup.allWyckoffLetters.split(""), 0, theGroup.getNWyckoffLetters()); return new ComboBoxCellEditor(theTable, WyckoffStrings); } @Override protected boolean canEdit(Object element) { return true; } @Override protected Object getValue(Object element) { int letterIndex; if (element instanceof XPDFAtom) letterIndex = XPDFSpaceGroup.allWyckoffLetters.indexOf(((XPDFAtom) element).getWyckoffLetter()); else letterIndex = 0; return letterIndex; } @Override protected void setValue(Object element, Object value) { int wyckoff; if (value instanceof Integer) { wyckoff = (Integer) value; } else { wyckoff = theGroup.getNWyckoffLetters()-1; } if (element instanceof XPDFAtom) { ((XPDFAtom) element).setWyckoffLetter(Character.toString(XPDFSpaceGroup.allWyckoffLetters.charAt(wyckoff))); } v.refresh(element); } }; } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { if (element instanceof XPDFAtom) return ((XPDFAtom) element).getWyckoffLetter(); else return "-"; } }; } @Override public String getName() { return "Wyckoff"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return false; } } private class MultiplicityColumnInterface implements ColumnInterface { @Override public EditingSupport get(ColumnViewer v) { return null; } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { if (element instanceof XPDFAtom) return Integer.toString(theGroup.getSiteMultiplicity(((XPDFAtom) element).getWyckoffLetter())); else return "-"; } }; } @Override public String getName() { return "Multiplicity"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return true; } } private static class OccupancyColumnInterface implements ColumnInterface { @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v){ @Override protected CellEditor getCellEditor(Object element) { return new TextCellEditor(((TableViewer) v).getTable()); } @Override protected boolean canEdit(Object element) { return true; } @Override protected Object getValue(Object element) { return (element instanceof XPDFAtom) ? Double.toString(((XPDFAtom) element).getOccupancy()) : null; } @Override protected void setValue(Object element, Object value) { if (element instanceof XPDFAtom && value instanceof String) { String valueString = (String) value; double occupancy = 0.0; try { occupancy = Double.parseDouble(valueString); } catch (NumberFormatException nFE) { ; } ((XPDFAtom) element).setOccupancy(occupancy); v.refresh(); } } }; } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return (element instanceof XPDFAtom) ? Double.toString(((XPDFAtom) element).getOccupancy()) : ""; } }; } @Override public String getName() { return "Occupancy"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return false; } } private static class adpColumnInterface implements ColumnInterface { @Override public EditingSupport get(final ColumnViewer v) { return new DummyEditingSupport(v); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return (element instanceof XPDFAtom) ? Double.toString(((XPDFAtom) element).getIsotropicDisplacement()) : ""; } }; } @Override public String getName() { return "Displacement"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return false; } } private class ElementComboViewerEditor extends ComboBoxViewerCellEditor { private final List<String> elementSymbol = Arrays.asList( new String[] { "?", "H","He","Li","Be","B","C","N","O","F","Ne", "Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca", "Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu","Zn", "Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y","Zr", "Nb","Mo","Tc","Ru","Rh","Pd","Ag","Cd","In","Sn", "Sb","Te","I","Xe","Cs","Ba","La","Ce","Pr","Nd", "Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb", "Lu","Hf","Ta","W","Re","Os","Ir","Pt","Au","Hg", "Tl","Pb","Bi","Po","At","Rn","Fr","Ra","Ac","Th", "Pa","U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm"} ); private static final int elementOffset = 1; private int z; public ElementComboViewerEditor(Composite parent) { super(parent); setContentProvider(new IStructuredContentProvider() { @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public void dispose() { } @Override public Object[] getElements(Object inputElement) { return Arrays.copyOfRange(elementSymbol.toArray(new String[elementSymbol.size()]), elementOffset, elementSymbol.size()); } }); // getViewer().getCombo().addKeyListener(new KeyListener() { // // @Override // public void keyPressed(KeyEvent e) { // // TODO Auto-generated method stub // // } // // @Override // public void keyReleased(KeyEvent e) { // // TODO Auto-generated method stub // // } // // }); } // Sets the new value, and returns it to the calling EditorSupport, and its getValue() method, hence the name. @Override protected Object doGetValue() { return getViewer().getCCombo().getSelectionIndex(); } // Sets the previous value from the EditorSupport setValue() method. @Override protected void doSetValue(Object element) { if (element instanceof String) z = elementSymbol.indexOf((String) element); else if (element instanceof Integer) z = (Integer) element; } } }