package org.archstudio.archedit.core;
import java.util.ArrayList;
import java.util.List;
import org.archstudio.eclipse.ui.editors.AbstractArchStudioEditor;
import org.archstudio.eclipse.ui.views.AbstractArchStudioOutlinePage;
import org.archstudio.resources.IResources;
import org.archstudio.swtutils.AutoResizeTableLayout;
import org.archstudio.xadl.XadlUtils;
import org.archstudio.xadl.bna.utils.XArchADTOperations;
import org.archstudio.xarchadt.IXArchADTFeature;
import org.archstudio.xarchadt.IXArchADTTypeMetadata;
import org.archstudio.xarchadt.ObjRef;
import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.ide.IGotoMarker;
public class ArchEditEditor extends AbstractArchStudioEditor<ArchEditMyxComponent> implements IGotoMarker {
public static final String[] COLUMN_NAMES = new String[] { "Name", "Value" };
public ArchEditEditor() {
super(ArchEditMyxComponent.class, ArchEditMyxComponent.EDITOR_NAME);
setBannerInfo(brick.getIcon(), "Syntax-Directed Architecture Editor");
setHasBanner(true);
}
@Override
protected AbstractArchStudioOutlinePage createOutlinePage() {
return new ArchEditOutlinePage(xarch, documentRootRef, resources);
}
@Override
public void createEditorContents(Composite parent) {
List<INodeInfo> selectedNodeInfos = null;
if (outlinePage != null) {
selectedNodeInfos = ((ArchEditOutlinePage) outlinePage).getSelectedNodeInfos();
}
if (selectedNodeInfos == null || selectedNodeInfos.size() == 0) {
Label lNothingSelected = new Label(parent, SWT.LEFT);
lNothingSelected.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
lNothingSelected.setFont(resources.getPlatformFont(IResources.PLATFORM_DEFAULT_FONT_ID));
lNothingSelected.setText("Select one or more elements in the outline view.");
}
else {
for (INodeInfo selectedNodeInfo : selectedNodeInfos) {
Label lElement = new Label(parent, SWT.LEFT);
lElement.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
lElement.setFont(resources.getPlatformFont(IResources.PLATFORM_HEADER_FONT_ID));
if (selectedNodeInfo instanceof IReferenceNodeInfo) {
IReferenceNodeInfo referenceNodeInfo = (IReferenceNodeInfo) selectedNodeInfo;
String headerLine = "Link: " + referenceNodeInfo.getFeatureName();
lElement.setText(headerLine.toString());
createDragSourceComposite(parent, referenceNodeInfo);
}
else if (selectedNodeInfo instanceof IElementNodeInfo) {
ObjRef selectedRef = ((IElementNodeInfo) selectedNodeInfo).getRef();
IXArchADTTypeMetadata typeMetadata = xarch.getTypeMetadata(selectedRef);
StringBuffer headerLine = new StringBuffer();
headerLine.append(XadlUtils.getDisplayName(xarch, selectedRef));
headerLine.append(": ");
headerLine.append(typeMetadata.getTypeName());
lElement.setText(headerLine.toString());
boolean hasAttribute = false;
for (IXArchADTFeature feature : typeMetadata.getFeatures().values()) {
if (feature.getType().equals(IXArchADTFeature.FeatureType.ATTRIBUTE)) {
hasAttribute = true;
break;
}
}
if (!hasAttribute) {
//No attributes.
Label lNoAttributes = new Label(parent, SWT.LEFT);
lNoAttributes.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
lNoAttributes.setFont(resources.getPlatformFont(IResources.PLATFORM_DEFAULT_FONT_ID));
lNoAttributes.setText("This element has no attributes.");
}
else {
TableViewer tv = new TableViewer(parent, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION
| SWT.NO_FOCUS);
tv.setContentProvider(new ViewContentProvider());
tv.setLabelProvider(new ViewLabelProvider());
tv.setInput(selectedRef);
Table table = tv.getTable();
TableColumn column = new TableColumn(table, SWT.LEFT);
column.setText(COLUMN_NAMES[0]);
TableColumn column2 = new TableColumn(table, SWT.LEFT);
column2.setText(COLUMN_NAMES[1]);
TableLayout tableLayout = new AutoResizeTableLayout(table);
tableLayout.addColumnData(new ColumnWeightData(30, true));
tableLayout.addColumnData(new ColumnWeightData(70, true));
table.setLayout(tableLayout);
table.setHeaderVisible(true);
table.setLinesVisible(true);
table.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
tv.setColumnProperties(COLUMN_NAMES);
CellEditor tce = new TextCellEditor(table);
tv.setCellEditors(new CellEditor[] { null, tce });
tv.setCellModifier(new ViewCellModifier(selectedRef));
tv.refresh();
}
}
}
}
}
protected class NameValuePair {
public String name;
public String value;
}
protected class ViewContentProvider implements IStructuredContentProvider {
public ViewContentProvider() {
}
@Override
public Object[] getElements(Object inputElement) {
List<String[]> l = new ArrayList<String[]>();
IXArchADTTypeMetadata typeMetadata = xarch.getTypeMetadata((ObjRef) inputElement);
for (IXArchADTFeature feature : typeMetadata.getFeatures().values()) {
if (feature.getType().equals(IXArchADTFeature.FeatureType.ATTRIBUTE)) {
Object value = xarch.get((ObjRef) inputElement, feature.getName());
l.add(new String[] { feature.getName(), value == null ? null : value.toString() });
}
}
return l.toArray();
}
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
@Override
public String getColumnText(Object obj, int index) {
return ((String[]) obj)[index];
}
@Override
public Image getColumnImage(Object obj, int index) {
return null;
}
@Override
public Image getImage(Object obj) {
return null;
}
}
class ViewCellModifier implements ICellModifier {
protected ObjRef ref;
public ViewCellModifier(ObjRef ref) {
this.ref = ref;
}
@Override
public boolean canModify(Object element, String property) {
return true;
}
@Override
public Object getValue(Object element, String property) {
if (element == null) {
return "";
}
if (element instanceof String[]) {
String[] elts = (String[]) element;
if (elts[1] == null) {
return "";
}
return elts[1].toString();
}
return null;
}
@Override
public void modify(Object element, String property, Object value) {
//SWT bug workaround
if (element instanceof Item) {
element = ((Item) element).getData();
}
if (element instanceof String[]) {
String[] elts = (String[]) element;
String propertyName = elts[0].toString();
String oldValue = null;
if (elts[1] != null) {
oldValue = elts[1].toString();
}
String newValue = null;
if (value != null) {
newValue = value.toString();
}
if (oldValue == null && newValue == null) {
//Do nothing
}
else if (oldValue != null && newValue == null) {
XArchADTOperations.set("Set", xarch, ref, propertyName, null);
}
else if (oldValue == null && newValue != null) {
set(propertyName, newValue);
}
else {
//Both non-null:
if (!oldValue.equals(newValue)) {
set(propertyName, newValue);
}
}
}
}
private void set(String featureName, String stringValue) {
IXArchADTTypeMetadata typeMetadata = xarch.getTypeMetadata(ref);
IXArchADTFeature feature = typeMetadata.getFeatures().get(featureName);
if (feature != null) {
try {
// If the feature is an enumeration type, then xarch.set will
// automatically try to convert it to an enum and throw
// IllegalArgumentException if it's not a valid value.
XArchADTOperations.set("Set", xarch, ref, featureName, stringValue);
}
catch (IllegalArgumentException iae) {
MessageBox messageBox = new MessageBox(parent.getShell(), SWT.OK | SWT.ICON_ERROR);
messageBox.setMessage("Invalid value for this field.");
messageBox.setText("Error");
messageBox.open();
}
}
else {
throw new RuntimeException("This shouldn't happen.");
}
}
}
public void createDragSourceComposite(Composite parent, IReferenceNodeInfo referenceNodeInfo) {
//Composite c = new Composite(parent, SWT.BORDER);
Group c = new Group(parent, SWT.SHADOW_ETCHED_IN);
GridLayout gl = new GridLayout(2, false);
gl.marginTop = 1;
gl.marginBottom = 5;
gl.marginLeft = 1;
gl.marginRight = 1;
gl.marginHeight = 1;
gl.marginWidth = 1;
gl.verticalSpacing = 0;
gl.horizontalSpacing = 0;
c.setLayout(gl);
c.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
Label il = new Label(c, SWT.LEFT | SWT.NO_FOCUS);
il.setImage(resources.getPlatformImage(ISharedImages.IMG_OBJS_INFO_TSK));
il.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
Label l = new Label(c, SWT.LEFT | SWT.NO_FOCUS);
l.setText("Drag this area to a target in the tree to quick-link.");
l.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
c.pack();
DragSource[] sources = new DragSource[] {
//new DragSource(il, DND.DROP_MOVE | DND.DROP_COPY),
new DragSource(l, DND.DROP_MOVE | DND.DROP_COPY), new DragSource(c, DND.DROP_MOVE | DND.DROP_COPY), };
final ObjRef fParentRef = referenceNodeInfo.getParentRef();
final String fFeatureName = referenceNodeInfo.getFeatureName();
for (DragSource source : sources) {
Transfer[] types = new Transfer[] { TextTransfer.getInstance() };
source.setTransfer(types);
source.addDragListener(new DragSourceListener() {
@Override
public void dragStart(DragSourceEvent event) {
event.doit = true;
}
@Override
public void dragSetData(DragSourceEvent event) {
if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
event.data = "$LINK$" + fFeatureName + "$" + xarch.getXPath(fParentRef);
}
}
@Override
public void dragFinished(DragSourceEvent event) {
if (event.detail == DND.DROP_MOVE) {
}
}
});
}
}
@Override
public void focusEditor(String editorName, ObjRef[] refs) {
super.focusEditor(editorName, refs);
}
@Override
@SuppressWarnings("rawtypes")
public Object getAdapter(Class key) {
if (key.equals(IGotoMarker.class)) {
return this;
}
return super.getAdapter(key);
}
@Override
public void gotoMarker(IMarker marker) {
ObjRef objRef = xarch.getByID(documentRootRef, marker.getAttribute(IMarker.LOCATION, null));
if (objRef != null) {
focusEditor(editorName, new ObjRef[] { objRef });
}
}
}