blob: 4be7a2dd81a0b7fe753b1142da5a3dfa99914cfd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2010 Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Sonatype, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.m2e.model.edit.pom.translators;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.m2e.model.edit.pom.PomFactory;
import org.eclipse.m2e.model.edit.pom.PropertyElement;
/**
* Translates a property list using the name and value instead of reflection.
*
* @author Mike Poindexter
*/
public class PropertiesAdapter extends ListAdapter {
protected List<PropertyElement> properties;
public PropertiesAdapter(SSESyncResource resc, Element containerNode, List<PropertyElement> properties) {
super(resc, containerNode, properties, null);
this.node = containerNode;
this.properties = properties;
}
@Override
public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue,
Object newValue, int pos) {
if(resource.isProcessEvents()) {
try {
resource.setProcessEvents(false);
if(INodeNotifier.ADD == eventType && newValue instanceof Element) {
if(notifier == node) {
IDOMElement addedElement = (IDOMElement) newValue;
int idx = absoluteIndexOf(node, addedElement);
if(idx == -1)
idx = 0;
properties.add(idx, createObject(addedElement));
}
} else if(INodeNotifier.REMOVE == eventType && oldValue instanceof Element) {
if(notifier == node) {
for(PropertyElement prop : properties) {
PropertyChildAdapter adapter = (PropertyChildAdapter) EcoreUtil.getExistingAdapter(prop,
PropertyChildAdapter.class);
if(adapter.getElement().equals(oldValue)) {
properties.remove(prop);
break;
}
}
}
} else if(changedFeature instanceof Text) {
if(notifier != node && notifier instanceof Element) {
Element e = (Element) notifier;
String name = e.getLocalName();
for(PropertyElement prop : properties) {
if(name.equals(prop.getName())) {
prop.setValue(getElementText(e));
}
}
}
}
} finally {
resource.setProcessEvents(true);
}
}
}
public void add(Object newValue, int position) {
final PropertyElement prop = (PropertyElement) newValue;
Element newElement = node.getOwnerDocument().createElement(prop.getName());
Text value = node.getOwnerDocument().createTextNode(prop.getValue());
newElement.appendChild(value);
if(position < 0)
position = 0;
Node n = getNthChildWithName(node, "*", position); //$NON-NLS-1$
if(n != null) {
node.insertBefore(newElement, n);
} else {
node.appendChild(newElement);
}
formatNode(newElement);
if(null == EcoreUtil.getExistingAdapter(prop, PropertyChildAdapter.class)) {
prop.eAdapters().add(new PropertyChildAdapter(prop, newElement));
}
((IDOMNode) newElement).addAdapter(this);
}
public void remove(Object oldValue, int position) {
if(position == -1)
position = 0;
Element n = getNthChildWithName(node, "*", position); //$NON-NLS-1$
if(n != null)
removeChildElement(n);
}
public PropertyElement createObject(Element child) {
PropertyElement propertyElement = PomFactory.eINSTANCE.createPropertyElement();
propertyElement.setName(child.getLocalName());
propertyElement.setValue(getElementText(child));
if(null == ((IDOMNode) child).getExistingAdapter(PropertiesAdapter.class)) {
((IDOMNode) child).addAdapter(this);
}
propertyElement.eAdapters().add(new PropertyChildAdapter(propertyElement, child));
return propertyElement;
}
@Override
public boolean isAdapterForType(Object type) {
return PropertiesAdapter.class.equals(type);
}
@Override
public void load() {
//MNGECLIPSE-2345, MNGECLIPSE-2694 when load is called on a list adapter already containing items,
// the old items shall be discarded to avoid duplicates.
properties.clear();
NodeList children = node.getChildNodes();
int nChildren = children.getLength();
for(int i = 0; i < nChildren; i++ ) {
Node child = children.item(i);
if(child instanceof Element) {
properties.add(createObject((Element) child));
}
}
}
@Override
public void save() {
for(PropertyElement o : properties) {
add(o, -1);
}
}
private class PropertyChildAdapter implements Adapter {
private Notifier target;
private PropertyElement property;
private Element element;
/**
* @param propertyElement
* @param container
*/
public PropertyChildAdapter(PropertyElement propertyElement, Element element) {
super();
this.property = propertyElement;
this.element = element;
}
public boolean isAdapterForType(Object type) {
return PropertyChildAdapter.class.equals(type);
}
public void notifyChanged(Notification notification) {
if(resource.isProcessEvents()) {
try {
resource.setProcessEvents(false);
Element newElement = node.getOwnerDocument().createElement(property.getName());
Text value = node.getOwnerDocument().createTextNode(property.getValue());
newElement.appendChild(value);
node.replaceChild(newElement, element);
formatNode(newElement);
this.element = newElement;
((IDOMNode) newElement).addAdapter(PropertiesAdapter.this);
} finally {
resource.setProcessEvents(true);
}
}
}
/**
* @return the target
*/
public Notifier getTarget() {
return target;
}
/**
* @param target the target to set
*/
public void setTarget(Notifier target) {
this.target = target;
}
/**
* @return the property
*/
public PropertyElement getProperty() {
return property;
}
/**
* @return the element
*/
public Element getElement() {
return element;
}
}
}