/******************************************************************************* * Copyright (c) 2012 VMware, Inc. * 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 * * Contributors: * VMware, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.config.ui.editors; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.wst.xml.core.internal.contentmodel.CMAttributeDeclaration; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement; import org.springframework.ide.eclipse.beans.core.namespaces.ToolAnnotationUtils; import org.springframework.ide.eclipse.beans.core.namespaces.ToolAnnotationUtils.ToolAnnotationData; import org.springframework.ide.eclipse.config.core.contentassist.SpringConfigContentAssistProcessor; import org.springframework.ide.eclipse.config.core.contentassist.XmlBackedContentProposalAdapter; import org.springframework.ide.eclipse.config.core.contentassist.providers.ToolAnnotationContentProposalProvider; import org.springframework.ide.eclipse.config.core.schemas.BeansSchemaConstants; import org.springframework.ide.eclipse.config.ui.widgets.AbstractAttributeWidget; import org.springframework.ide.eclipse.config.ui.widgets.TextAttribute; import org.springframework.ide.eclipse.config.ui.widgets.TextAttributeProposalAdapter; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * @author Leo Dos Santos */ @SuppressWarnings("restriction") public class SpringConfigDetailsSectionPart extends AbstractConfigDetailsSectionPart { private class CMAttributeDeclarationComparator implements Comparator<CMAttributeDeclaration> { public int compare(CMAttributeDeclaration o1, CMAttributeDeclaration o2) { String name1 = o1.getNodeName(); String name2 = o2.getNodeName(); boolean required1 = processor.isRequiredAttribute(o1); boolean required2 = processor.isRequiredAttribute(o2); // Sort: // 1. ID attributes at the top // 2. followed by required attributes in alphabetical order // 3. followed by other attributes in alphabetical order if (name1.equalsIgnoreCase(BeansSchemaConstants.ATTR_ID)) { return -1; } if (name2.equalsIgnoreCase(BeansSchemaConstants.ATTR_ID)) { return 1; } if (required1 && required2) { return name1.compareToIgnoreCase(name2); } if (required1) { return -1; } if (required2) { return 1; } return name1.compareToIgnoreCase(name2); } } private final SpringConfigContentAssistProcessor processor; private final List<AbstractAttributeWidget> widgets; private final List<XmlBackedContentProposalAdapter> adapters; private List<CMAttributeDeclaration> attrDecls; public SpringConfigDetailsSectionPart(AbstractConfigEditor editor, IDOMElement input, Composite parent, FormToolkit toolkit) { super(editor, input, parent, toolkit); processor = editor.getXmlProcessor(); widgets = new ArrayList<AbstractAttributeWidget>(); adapters = new ArrayList<XmlBackedContentProposalAdapter>(); attrDecls = processor.getAttributeDeclarations(input); } protected void addAdapter(XmlBackedContentProposalAdapter adapter) { adapters.add(adapter); } private void addComboAttribute(Composite client, String attr, String[] enumStrs, boolean required) { boolean hasEmptyStr = false; String[] enumStrsCopy = new String[enumStrs.length + 1]; enumStrsCopy[0] = ""; //$NON-NLS-1$ for (int i = 0; i < enumStrs.length; i++) { enumStrsCopy[i + 1] = enumStrs[i]; if (enumStrs[0].trim().length() == 0) { hasEmptyStr = true; } } if (!hasEmptyStr) { enumStrs = enumStrsCopy; } widgets.add(createComboAttribute(client, attr, enumStrs, required)); } /** * This method is called automatically when the details section is created. * Clients may override to add their own custom widgets with hyperlinks and * content proposals. Must return true if a widget was created, and false * otherwise so that the page can create a plain text field for the * attribute. * * @param client the parent composite * @param attr the attribute name * @param required denotes whether this is a required field * @return true if an attribute widget was created, false otherwise */ protected boolean addCustomAttribute(Composite client, String attr, boolean required) { return false; } private void addTextAttribute(Composite client, String attr, boolean required) { boolean widgetCreated = false; List<Element> appInfo = ToolAnnotationUtils.getApplicationInformationElements(getInput(), attr); if (!appInfo.isEmpty()) { for (Element element : appInfo) { NodeList children = element.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node annotation = children.item(i); ToolAnnotationData data = ToolAnnotationUtils.getToolAnnotationData(annotation); if (!widgetCreated) { TextAttribute attrWidget = null; if (data.getExpectedType() != null && data.getExpectedType().equalsIgnoreCase(Class.class.getName())) { attrWidget = createClassAttribute(client, attr, true, required); } else if (data.getKind() != null || data.getExpectedMethodType() != null || data.getExpectedMethodRef() != null || data.getExpectedMethodExpression() != null) { attrWidget = createToolAnnotationAttribute(client, attr, required); } if (attrWidget != null) { widgets.add(attrWidget); adapters.add(new TextAttributeProposalAdapter(attrWidget, new ToolAnnotationContentProposalProvider(getInput(), attr))); widgetCreated = true; } } } } } if (!widgetCreated) { if (!addCustomAttribute(client, attr.toLowerCase(), required)) { widgets.add(createTextAttribute(client, attr, required)); } } } protected void addWidget(AbstractAttributeWidget widget) { widgets.add(widget); } @Override protected void createAttributes(Composite client) { if (attrDecls.isEmpty() && processor.allowsCharacterData(getInput())) { widgets.add(createTextArea(client, getInput().getLocalName())); } else { Collections.sort(attrDecls, new CMAttributeDeclarationComparator()); for (CMAttributeDeclaration attrDecl : attrDecls) { boolean required = processor.isRequiredAttribute(attrDecl); String attr = attrDecl.getNodeName(); String[] enumStrs = attrDecl.getAttrType().getEnumeratedValues(); if (enumStrs != null && enumStrs.length > 0) { addComboAttribute(client, attr, enumStrs, required); } else { addTextAttribute(client, attr, required); } } } } @Override public void refresh() { for (AbstractAttributeWidget widget : widgets) { widget.update(); } for (XmlBackedContentProposalAdapter adapter : adapters) { adapter.update(getInput()); } super.refresh(); } @Override public boolean setFormInput(Object input) { boolean result = super.setFormInput(input); attrDecls = processor.getAttributeDeclarations(getInput()); return result; } }