/**
*
*/
/*******************************************************************************
* Copyright (c) 2010 SAP AG.
* 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:
* Emil Simeonov - initial API and implementation.
* Dimitar Donchev - initial API and implementation.
* Dimitar Tenev - initial API and implementation.
* Nevena Manova - initial API and implementation.
* Georgi Konstantinov - initial API and implementation.
*******************************************************************************/
package org.eclipse.wst.sse.sieditor.command.emf.xsd;
import java.util.HashSet;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.wst.sse.core.internal.encoding.CommonEncodingPreferenceNames;
import org.eclipse.wst.xml.core.internal.XMLCorePlugin;
import org.eclipse.wst.xsd.ui.internal.common.commands.BaseCommand;
import org.eclipse.xsd.XSDSchema;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import org.eclipse.wst.sse.sieditor.command.common.AbstractNotificationOperation;
import org.eclipse.wst.sse.sieditor.model.api.IXSDModelRoot;
import org.eclipse.wst.sse.sieditor.model.utils.EmfModelPatcher;
import org.eclipse.wst.sse.sieditor.model.utils.EmfXsdUtils;
import org.eclipse.wst.sse.sieditor.model.xsd.api.ISchema;
public class EnsureSchemaElementCommand extends AbstractNotificationOperation {
private final boolean hasXmlTag;
private final boolean hasSchemaElement;
/**
* @param schema
* The model root in whos enviroment the commands are executed is
* retrieved from the schema.
* @see AbstractNotificationOperation
*/
public EnsureSchemaElementCommand(final ISchema schema, final String operationLabel) {
super(schema.getModelRoot(), schema, operationLabel);
final XSDSchema xsdSchema = schema.getComponent();
hasXmlTag = EmfXsdUtils.hasXmlTag(xsdSchema.getDocument());
hasSchemaElement = xsdSchema.getElement() != null;
}
@Override
public boolean canExecute() {
final ISchema schema = (ISchema) getModelObjects()[0];
if (schema == null) {
return false;
}
final XSDSchema component = schema.getComponent();
return (component != null) && (component.getDocument() != null) && !hasSchemaElement && super.canExecute();
}
protected void patchModelAfterchange(final Node documentNode) {
final HashSet<Node> nodesList = new HashSet<Node>();
if (documentNode instanceof Document) {
nodesList.add(documentNode);
EmfModelPatcher.instance().patchEMFModelAfterDomChange((IXSDModelRoot) getModelRoot(), nodesList);
}
}
@SuppressWarnings( { "restriction" })
private static final class BaseCommandExposer extends org.eclipse.wst.xsd.ui.internal.common.commands.BaseCommand {
public static void exposeEnsureSchemaElement(final XSDSchema schema) {
ensureSchemaElement(schema);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.wst.sse.sieditor.command.common.AbstractNotificationOperation
* #run(org.eclipse.core.runtime.IProgressMonitor,
* org.eclipse.core.runtime.IAdaptable)
*/
@Override
public IStatus run(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
final XSDSchema xsdSchema = ((ISchema) getModelObjects()[0]).getComponent();
if (!hasXmlTag) {
ensureXmlElement(xsdSchema);
}
BaseCommandExposer.exposeEnsureSchemaElement(xsdSchema);
xsdSchema.elementChanged(xsdSchema.getElement());
patchModelAfterchange(xsdSchema.getDocument());
if (!hasSchemaElement)
xsdSchema.eNotify(new ENotificationImpl((InternalEObject) xsdSchema, Notification.ADD, null, null, xsdSchema));
return Status.OK_STATUS;
}
// =========================================================
// eclipse bug 321851 workarounds:
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=321851
// =========================================================
/**
* this is a workaround for the BaseCommand#ensureSchemaElement method. this
* method is first adding the <schema> element and then - the <?xml>
* element. The <?xml> node is the first child node of the document, so this
* was the cause of a large number of DOM change events.
*
* the following lines of code are copy from BaseCommand#ensureXMLDirective
* method
*/
private void ensureXmlElement(final XSDSchema xsdSchema) {
final Node firstChild = xsdSchema.getDocument().getFirstChild();
final ProcessingInstruction xmlDeclaration = getXMLDeclaration(xsdSchema.getDocument());
xsdSchema.getDocument().insertBefore(xmlDeclaration, firstChild);
final Text textNode = xsdSchema.getDocument().createTextNode(System.getProperty("line.separator")); //$NON-NLS-1$
xsdSchema.getDocument().insertBefore(textNode, firstChild);
// explicitly fire an ADD event for the added xml directive
xsdSchema.eNotify(new ENotificationImpl((InternalEObject) xsdSchema, Notification.ADD, null, null, xmlDeclaration));
}
/**
* this method is copy of {@link BaseCommand#getXMLDeclaration}
*
* @param document
* @return
*/
private static ProcessingInstruction getXMLDeclaration(final Document document) {
final Preferences preference = XMLCorePlugin.getDefault().getPluginPreferences();
String charSet = preference.getString(CommonEncodingPreferenceNames.OUTPUT_CODESET);
if (charSet == null || charSet.trim().equals("")) { //$NON-NLS-1$
charSet = "UTF-8"; //$NON-NLS-1$
}
final ProcessingInstruction xmlDeclaration = document.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"" //$NON-NLS-1$ //$NON-NLS-2$
+ charSet + "\""); //$NON-NLS-1$
return xmlDeclaration;
}
}