/* * Copyright 2015 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.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.TreeSet; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.LocalSelectionTransfer; 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.DialogCellEditor; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; 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.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSourceAdapter; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.TableColumn; /** * Display and edit phases for the XPDF project * @author Timothy Spain, timothy.spain@diamond.ac.uk * */ class PhaseGroupedTable { private List<XPDFPhase> phases; private XPDFGroupedTable groupedTable; private TreeSet<Integer> usedIDs; private SampleGroupedTable sampleTable; private List<XPDFPhase> visiblePhases; /** * Create an {@link XPDFGroupedTable} in Composite parent. * @param parent * Composite to receive the grouped table. Does not need a {@link ColumnTableLayout}. * @param style * Style bits for the underlying table. * */ public PhaseGroupedTable(Composite parent, int style) { phases = new ArrayList<XPDFPhase>(); visiblePhases = new ArrayList<XPDFPhase>(); groupedTable = new XPDFGroupedTable(parent, SWT.NONE); List<String> groupNames = new ArrayList<String>(); List<ColumnInterface> columnInterfaces = new ArrayList<ColumnInterface>(); List<List<ColumnInterface>> groupedColumnInterfaces = new ArrayList<List<ColumnInterface>>(); groupNames.add("Phase Identification"); columnInterfaces.add(new NameColumnInterface()); columnInterfaces.add(new CodeColumnInterface()); groupedColumnInterfaces.add(columnInterfaces); groupNames.add("Physical Form"); columnInterfaces = new ArrayList<ColumnInterface>(); columnInterfaces.add(new FormColumnInterface()); columnInterfaces.add(new CrystalColumnInterface()); groupedColumnInterfaces.add(columnInterfaces); groupNames.add("Unit cell"); columnInterfaces = new ArrayList<ColumnInterface>(); columnInterfaces.add(new GroupColumnInterface()); columnInterfaces.add(new UnitCellColumnInterface(0)); columnInterfaces.add(new UnitCellColumnInterface(1)); columnInterfaces.add(new UnitCellColumnInterface(2)); columnInterfaces.add(new InternalAngleColumnInterface(0)); columnInterfaces.add(new InternalAngleColumnInterface(1)); columnInterfaces.add(new InternalAngleColumnInterface(2)); groupedColumnInterfaces.add(columnInterfaces); groupNames.add("Properties"); columnInterfaces = new ArrayList<ColumnInterface>(); columnInterfaces.add(new CompositionColumnInterface()); columnInterfaces.add(new DensityColumnInterface()); groupedColumnInterfaces.add(columnInterfaces); groupNames.add("‍"); columnInterfaces = new ArrayList<ColumnInterface>(); columnInterfaces.add(new CommentColumnInterface()); 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); if (colI.getSelectionAdapter(this, col) != null) col.getColumn().addSelectionListener(colI.getSelectionAdapter(this, col)); } } PhaseContentProvider contentProvider = new PhaseContentProvider(); groupedTable.setContentProvider(contentProvider); // For now, drag support only. Drop support for phase-defining CIF files will eventually be added groupedTable.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY, new Transfer[]{LocalSelectionTransfer.getTransfer()}, new LocalDragSupportListener(groupedTable)); // phases with test data List<XPDFPhase> testPhases = new ArrayList<XPDFPhase>(); // testPhases.add(SampleTestData.createTestPhase("Crown Glass")); testPhases.add(SampleTestData.createTestPhase("Flint Glass")); testPhases.add(SampleTestData.createTestPhase("microcline")); testPhases.add(SampleTestData.createTestPhase("cryolite")); testPhases.add(SampleTestData.createTestPhase("ilmenite")); testPhases.add(SampleTestData.createTestPhase("beryllium")); addPhases(testPhases); } // Generate a new id private int getUniqueID() { final int lowestID = 2564; if (usedIDs == null) usedIDs = new TreeSet<Integer>(); int theID = (usedIDs.isEmpty()) ? lowestID : usedIDs.last()+1; usedIDs.add(theID); return theID; } private class PhaseContentProvider implements IStructuredContentProvider { @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public Object[] getElements(Object inputElement) { if (visiblePhases == null || visiblePhases.size() == 0) return phases.toArray(new XPDFPhase[]{}); else return visiblePhases.toArray(new XPDFPhase[]{}); } } /** * Sets the input of the delegated viewer objects to the List of phases. */ public void setInput() { groupedTable.setInput(phases); } /** * Sets the {@link Layout} data of the underlying Composite. * @param layout */ public void setLayoutData(Object layout) { groupedTable.setLayoutData(layout); } private SelectionAdapter getColumnSelectionAdapter(final TableColumn tableColumn, final Comparator<XPDFPhase> comparator) { return new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { if (comparator == null) return; // Find the present sorted column, if any TableColumn presentSorted = null; int oldSortDirection = SWT.NONE; presentSorted = groupedTable.getSortColumn(); oldSortDirection = groupedTable.getSortDirection(); groupedTable.setSortColumn(null); groupedTable.setSortDirection(SWT.NONE); int newSortDirection = SWT.DOWN; // If the same column is sorted as is now selected, then reverse the sorting if (presentSorted == tableColumn) newSortDirection = (oldSortDirection == SWT.UP) ? SWT.DOWN : SWT.UP; // Do the sort Collections.sort(phases, comparator); if (newSortDirection == SWT.UP) Collections.reverse(phases); groupedTable.setSortColumn(tableColumn); groupedTable.setSortDirection(newSortDirection); groupedTable.refresh(); } }; } /** * Sets the sample table to which this phase table refers. * @param sampleTable * the sample table to which this phase table refers. */ public void setSampleTable(SampleGroupedTable sampleTable) { this.sampleTable = sampleTable; } /** * Adds new phases. * @param addedPhases * Collection of phases to add to the internal list */ public void addPhases(Collection<XPDFPhase> addedPhases) { for (XPDFPhase phase: addedPhases) { phase.setId(getUniqueID()); phases.add(phase); } groupedTable.refresh(); } /** * Gets all the phases. * @return all the phases in the table, as a List. */ public List<XPDFPhase> getAll() { return phases; } /** * Removes several phases from the table. * @param phasesToGo * The objects of the phases to be removed. */ public void removeAll(Collection<XPDFPhase> phasesToGo) { phases.removeAll(phasesToGo); refresh(); } /** * Gets the phases selected in the table. * @return A List of all the phases selected in the table. */ public List<XPDFPhase> getSelectedPhases() { List<XPDFPhase> selectedPhases= new ArrayList<XPDFPhase>(); ISelection selection = groupedTable.getSelection(); // No items? return, having done nothing. if (selection.isEmpty()) return selectedPhases; // If it is not an IStructureSelection, then I don't know what to do with it. if (!(selection instanceof IStructuredSelection)) return selectedPhases; // Get the list of all selected data List<?> selectedData = ((IStructuredSelection) selection).toList(); for (Object datum : selectedData) if (datum instanceof XPDFPhase) selectedPhases.add((XPDFPhase) datum); return selectedPhases; } /** * Add a context menu to this table. * @param menuManager context menu to add. */ public void createContextMenu(MenuManager menuManager) { groupedTable.createContextMenu(menuManager); } /** * Sets the phases that should be visible. * @param visiblePhases * Collection of the phases that should be visible in the table. */ public void setVisiblePhases(Collection<XPDFPhase> visiblePhases) { this.visiblePhases.clear(); for (XPDFPhase phase : visiblePhases) { // Ensure any phases set to be visible exist in the list of all phases if (!phases.contains(phase)) { phase.setId(getUniqueID()); phases.add(phase); } this.visiblePhases.add(phase); } } private class LocalDragSupportListener extends DragSourceAdapter { private XPDFGroupedTable gT; public LocalDragSupportListener(XPDFGroupedTable gT) { this.gT = gT; } @Override public void dragSetData(DragSourceEvent event) { LocalSelectionTransfer.getTransfer().setSelection(gT.getSelection()); } } private interface ColumnInterface extends EditingSupportFactory { public SelectionAdapter getSelectionAdapter(final PhaseGroupedTable tab, 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(PhaseGroupedTable tab, // TableViewerColumn col) { // return DummySelectionAdapter.get(tab, 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 DummySelectionAdapter { public static SelectionAdapter get(PhaseGroupedTable tab, TableViewerColumn col) { return tab.getColumnSelectionAdapter(col.getColumn(), new Comparator<XPDFPhase>() { @Override public int compare(XPDFPhase o1, XPDFPhase o2) { return 0; } }); } } private static class DummyLabelProvider extends ColumnLabelProvider { String text; public DummyLabelProvider(String text) { this.text = text; } @Override public String getText(Object element) { return text; } } private static class NameColumnInterface 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) { XPDFPhase phase = (XPDFPhase) element; return (phase != null && phase.getName() != null) ? phase.getName() : ""; } @Override protected void setValue(Object element, Object value) { ((XPDFPhase) element).setName( (value != null) ? (String) value : ""); v.refresh(); } }; } @Override public SelectionAdapter getSelectionAdapter(final PhaseGroupedTable tab, final TableViewerColumn col) { return tab.getColumnSelectionAdapter(col.getColumn(), new Comparator<XPDFPhase>() { @Override public int compare(XPDFPhase o1, XPDFPhase o2) { return o1.getName().compareTo(o2.getName()); } }); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return ((XPDFPhase) element).getName(); } }; } @Override public String getName() { return "Name"; } @Override public int getWeight() { return 20; } @Override public boolean presentAsUneditable(Object element) { return false; } } private static class CodeColumnInterface implements ColumnInterface { @Override public EditingSupport get(ColumnViewer v) { return new DummyEditingSupport(v); } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return tab.getColumnSelectionAdapter(col.getColumn(), new Comparator<XPDFPhase>() { @Override public int compare (XPDFPhase o1, XPDFPhase o2) { return Integer.compare(o1.getId(), o2.getId()); } }); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return "P"+String.format("%05d", ((XPDFPhase) element).getId()); } }; } @Override public String getName() { return "Code"; } @Override public int getWeight() { return 5; } @Override public boolean presentAsUneditable(Object element) { return false; } } private static class FormColumnInterface implements ColumnInterface { @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v) { @Override protected void setValue(Object element, Object value) { XPDFPhase phase = (XPDFPhase) element; XPDFPhaseForm oldForm = phase.getForm(); XPDFPhaseForm newForm = XPDFPhaseForm.get(XPDFPhaseForm.Forms.values()[(int) value]); phase.setForm(newForm); if (oldForm != newForm) if (newForm == XPDFPhaseForm.get(XPDFPhaseForm.Forms.CRYSTALLINE)) phase.setCrystalSystem(CrystalSystem.get(0)); // Triclinic else phase.setCrystalSystem(null); v.refresh(); } @Override protected Object getValue(Object element) { return ((XPDFPhase) element).getForm().getOrdinal(); } @Override protected CellEditor getCellEditor(Object element) { return new ComboBoxCellEditor(((TableViewer) v).getTable(), XPDFPhaseForm.getNames()); } @Override protected boolean canEdit(Object element) { return true; } }; } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return DummySelectionAdapter.get(tab, col); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return ((XPDFPhase) element).getForm().getName(); } }; } @Override public String getName() { return "Form"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return false; } } private static class CrystalColumnInterface implements ColumnInterface { @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v) { @Override protected CellEditor getCellEditor(Object element) { return new ComboBoxCellEditor(((TableViewer) v).getTable(), CrystalSystem.getNames()); } @Override protected boolean canEdit(Object element) { return ((XPDFPhase) element).isCrystalline(); } @Override protected Object getValue(Object element) { return ((XPDFPhase) element).getCrystalSystem().getOrdinal(); } @Override protected void setValue(Object element, Object value) { XPDFPhase phase = (XPDFPhase) element; CrystalSystem oldSystem = phase.getCrystalSystem(); CrystalSystem newSystem = CrystalSystem.get((int) value); phase.setCrystalSystem(newSystem); v.refresh(); } }; } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return DummySelectionAdapter.get(tab, col); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return (!presentAsUneditable(element)) ? ((XPDFPhase) element).getCrystalSystem().getName() : "-"; } }; } @Override public String getName() { return "Crystal System"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return !((XPDFPhase) element).isCrystalline(); } } private static class GroupColumnInterface implements ColumnInterface { @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v){ @Override protected CellEditor getCellEditor(Object element) { XPDFPhase phase = (XPDFPhase) element; List<String> groupNames = new LinkedList<String>(); for (XPDFSpaceGroup group : phase.getCrystalSystem().getGroups()) groupNames.add(group.getName()); return new ComboBoxCellEditor(((TableViewer) v).getTable(), groupNames.toArray(new String[groupNames.size()])); } @Override protected boolean canEdit(Object element) { return ((XPDFPhase) element).isCrystalline(); } @Override protected Object getValue(Object element) { XPDFPhase phase = (XPDFPhase) element; if (phase.getSpaceGroup() == null) return 0; else return phase.getSpaceGroup().getNumber() - phase.getCrystalSystem().getGroups().get(0).getNumber(); } @Override protected void setValue(Object element, Object value) { XPDFPhase phase = (XPDFPhase) element; int ordinalInSystem = (int) value; int firstInSystem = phase.getCrystalSystem().getGroups().get(0).getNumber(); phase.setSpaceGroup(firstInSystem + ordinalInSystem); v.refresh(); } }; } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return DummySelectionAdapter.get(tab, col); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { XPDFPhase phase = (XPDFPhase) element; if (phase.isCrystalline()) if (phase.getSpaceGroup() != null) return phase.getSpaceGroup().getName(); return "-"; } }; } @Override public String getName() { return "Space Group"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return !((XPDFPhase) element).isCrystalline(); } } private static class UnitCellColumnInterface implements ColumnInterface { static final String[] axisNames = {"a", "b", "c"}; final int axisIndex; static final int nDim = 3; // minimum unit cell volume of 6 ų, approximately the volume occupied // by one carbon atom within the diamond structure (not the diamond // unit cell volume) static final double minimumVolume = 6.0; public UnitCellColumnInterface(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 !presentAsUneditable(element); } @Override protected Object getValue(Object element) { XPDFPhase phase = (XPDFPhase) element; int axisIndexData = phase.getSpaceGroup().getSystem().getAxisIndices()[axisIndex]; double cellLength = phase.getUnitCellLength(axisIndexData); return (cellLength == 0.0) ? axisNames[axisIndexData] : Double.toString(cellLength); } @Override protected void setValue(Object element, Object value) { double newLength; try { newLength = Double.parseDouble((String) value); } catch (NumberFormatException nFE) { // Do nothing, get out of here return; } // validation: if an out of range number was entered, ignore the change, and return // minimum unit cell edge is 0 if (newLength <= 0.0) return; // And check that the new length does not result in too small a unit cell. XPDFPhase phase = (XPDFPhase) element, tempPhase = new XPDFPhase(phase); tempPhase.setUnitCellLength(axisIndex, newLength); double newVolume = tempPhase.getUnitCellVolume(); // if the new unit cell volume is too small, return, having set nothing. Allow 0, though if ( newVolume < 6.0 && newVolume != 0.0) { System.err.println("Unit cell volume unphysically small, V = " + newVolume + " ų."); return; } phase.setUnitCellLength(axisIndex, newLength); v.refresh(); } }; } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return DummySelectionAdapter.get(tab, col); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { XPDFPhase phase = (XPDFPhase) element; String label; if (!phase.isCrystalline() || phase.getSpaceGroup() == null) label = "-"; else { int axisIndexData = phase.getSpaceGroup().getSystem().getAxisIndices()[axisIndex]; double cellLength = phase.getUnitCellLength(axisIndexData); if (cellLength == 0.0) label = axisNames[axisIndexData]; else label = Double.toString(cellLength); } return label; } @Override public Font getFont(Object element) { return (presentAsUneditable((XPDFPhase) element)) ? JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT) : JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT); } @Override public Color getForeground(Object element) { String axisString = getText(element); for (String axisName : axisNames) if (axisName.equals(axisString)) return new Color(null, 255, 0, 0); return new Color(null, 0, 0, 0); } }; } @Override public String getName() { return axisNames[axisIndex]+" (Å)"; } @Override public int getWeight() { return 5; } @Override public boolean presentAsUneditable(Object element) { XPDFPhase phase = (XPDFPhase) element; return !phase.isCrystalline() || phase.getSpaceGroup() == null || phase.getSpaceGroup().getSystem().getAxisIndices()[axisIndex] != axisIndex; } } private static class InternalAngleColumnInterface implements ColumnInterface { static final String[] angleNames = {"α", "β", "γ"}; int angleIndex; public InternalAngleColumnInterface(int angleIndex) { this.angleIndex = angleIndex; } @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 !presentAsUneditable(element); } @Override protected Object getValue(Object element) { XPDFPhase phase = (XPDFPhase) element; int rawAngle = phase.getSpaceGroup().getSystem().getFixedAngles()[angleIndex]; if (rawAngle > 0) { return Integer.toString(rawAngle); } else { int angleAxis = -rawAngle-1; double angle = phase.getUnitCellAngle(angleAxis); return (angle == 0.0) ? angleNames[angleAxis] : Double.toString(angle); } } @Override protected void setValue(Object element, Object value) { double newAngle; try { newAngle = Double.parseDouble((String) value); } catch (NumberFormatException nFE) { // Do nothing, get out of here return; } // If the newly set angle is out of range, then return, having done nothing. if (newAngle <= 0.0 || newAngle > 180.0) return; ((XPDFPhase) element).setUnitCellAngle(angleIndex, newAngle); v.refresh(); } }; } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return DummySelectionAdapter.get(tab, col); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { XPDFPhase phase = (XPDFPhase) element; if (!phase.isCrystalline() || phase.getSpaceGroup() == null) { // Non-crystalline phase return "-"; } else { int rawAngle = phase.getSpaceGroup().getSystem().getFixedAngles()[angleIndex]; if (rawAngle > 0) { return Integer.toString(rawAngle); } else { int angleAxis = -rawAngle-1; double angle = phase.getUnitCellAngle(angleAxis); return (angle == 0.0) ? angleNames[angleAxis] : Double.toString(angle); } } } @Override public Font getFont(Object element) { return (presentAsUneditable((XPDFPhase) element)) ? JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT) : JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT); } @Override public Color getForeground(Object element) { String angleString = getText(element); for (String angleName : angleNames) if (angleName.equals(angleString)) return new Color(null, 255, 0, 0); return new Color(null, 0, 0, 0); } }; } @Override public String getName() { return angleNames[angleIndex] + " (°)"; } @Override public int getWeight() { return 5; } @Override public boolean presentAsUneditable(Object element) { XPDFPhase phase = (XPDFPhase) element; return !phase.isCrystalline() || // No unit cell, due to not being a crystal phase.getSpaceGroup() == null || // -"-, due to undefined space group phase.getSpaceGroup().getSystem().getFixedAngles()[angleIndex] > 0 || // fixed angles -phase.getSpaceGroup().getSystem().getFixedAngles()[angleIndex]-1 != angleIndex; // adjustable angles, defined by other dimensions } } private static class CompositionColumnInterface implements ColumnInterface { @Override public EditingSupport get(final ColumnViewer v) { return new EditingSupport(v) { @Override protected CellEditor getCellEditor(final Object element) { return new DialogCellEditor(((TableViewer) v).getTable()) { private UnitCellDialog unitCell; private List<XPDFAtom> atoms; private boolean wasOkayed; @Override protected Object openDialogBox(Control cellEditorWindow) { unitCell = new UnitCellDialog(cellEditorWindow.getShell()); unitCell.createDialogArea(((TableViewer) v).getTable()); unitCell.setAllAtoms(atoms); if (element instanceof XPDFPhase) unitCell.setSpaceGroup(((XPDFPhase) element).getSpaceGroup()); wasOkayed = true; if (unitCell.open() != Window.OK) wasOkayed = false; return null; } @Override protected Button createButton(Composite parent) { Button button = super.createButton(parent); button.setText("+"); return button; } @Override protected Object doGetValue() { if (unitCell != null && wasOkayed) { List<XPDFAtom> allAtoms = new ArrayList<XPDFAtom>(unitCell.getAllAtoms()), badAtoms = new ArrayList<XPDFAtom>(); for (XPDFAtom atom : allAtoms) if (atom.getAtomicNumber() < 1) badAtoms.add(atom); allAtoms.removeAll(badAtoms); return allAtoms; } else return new ArrayList<XPDFAtom>(atoms); } @Override protected void doSetValue(Object value) { if (value instanceof List<?>) atoms = ((List<XPDFAtom>) value); } }; } @Override protected boolean canEdit(Object element) { return true; } @Override protected Object getValue(Object element) { if (element instanceof XPDFPhase) return ((XPDFPhase) element).getAllAtoms(); else return getLabelProvider().getText(element); } @Override protected void setValue(Object element, Object value) { if (value instanceof List<?>) { List<?> genericList= (List<?>) value; List<XPDFAtom> atomList; try { atomList = (List<XPDFAtom>) genericList; } catch (ClassCastException cCE) { return; } XPDFPhase phase = (XPDFPhase) element; phase.clearAtoms(); phase.addAllAtoms(atomList); } v.refresh(); return; } }; } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return DummySelectionAdapter.get(tab, col); } @Override public ColumnLabelProvider getLabelProvider() { // return new DummyLabelProvider("Elements!"); return new ColumnLabelProvider() { @Override public String getText(Object element) { return (element instanceof XPDFPhase) ? ((XPDFPhase) element).getHallNotation(true, true) : "N/A"; } @Override public Font getFont(Object element) { return (presentAsUneditable(element)) ? JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT) : JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT); } }; } @Override public String getName() { return "Composition"; } @Override public int getWeight() { return 20; } @Override public boolean presentAsUneditable(Object element) { return false; } } private static class DensityColumnInterface implements ColumnInterface { @Override public EditingSupport get(ColumnViewer v) { return new DummyEditingSupport(v); } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return DummySelectionAdapter.get(tab, col); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { if (element instanceof XPDFPhase) { DecimalFormat threeDP = new DecimalFormat("0.000"); return threeDP.format(((XPDFPhase) element).getDensity()); } else { return "-"; } } @Override public Font getFont(Object element) { return (presentAsUneditable((XPDFPhase) element)) ? JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT) : JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT); } }; } @Override public String getName() { return "Density (g cm⁻³)"; } @Override public int getWeight() { return 10; } @Override public boolean presentAsUneditable(Object element) { return ((XPDFPhase) element).isCrystalline(); } } private static class CommentColumnInterface 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 != null) ? ((XPDFPhase) element).getComment() : ""; } @Override protected void setValue(Object element, Object value) { if (!(element instanceof XPDFPhase)) return; XPDFPhase phase = (XPDFPhase) element; if (value != null) { phase.clearComment(); phase.addComment((String) value); } v.refresh(); } }; } @Override public SelectionAdapter getSelectionAdapter(PhaseGroupedTable tab, TableViewerColumn col) { return DummySelectionAdapter.get(tab, col); } @Override public ColumnLabelProvider getLabelProvider() { return new ColumnLabelProvider() { @Override public String getText(Object element) { return ((XPDFPhase) element).getComment(); } }; } @Override public String getName() { return "Comment"; } @Override public int getWeight() { return 30; } @Override public boolean presentAsUneditable(Object element) { return false; } } /** * Refreshes the internal table. */ public void refresh() { groupedTable.refresh(); } }