/*******************************************************************************
* Copyright (c) 2009, 2010 Innovation Gate GmbH.
* 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:
* Innovation Gate GmbH - initial API and implementation
******************************************************************************/
package de.innovationgate.eclipse.editors.all;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnmappableCharacterException;
import java.nio.charset.UnsupportedCharsetException;
import org.eclipse.core.filebuffers.manipulation.ContainerCreator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.editors.text.FileDocumentProvider;
import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
import de.innovationgate.eclipse.editors.Plugin;
import de.innovationgate.eclipse.utils.wga.WGADesignStructureHelper;
/**
* this document provider enforces WGADesign encoding for
* all WGADesign-Files
*
*
*/
public class WGADesignFileDocumentProvider extends FileDocumentProvider {
private String _encoding = null;
@Override
protected IDocument createDocument(Object element) throws CoreException {
// determine design encoding
if (element instanceof IFileEditorInput) {
IFile file = ((IFileEditorInput) element).getFile();
if (file != null) {
if (file.getFileExtension().equalsIgnoreCase(".properties")) {
_encoding = "ISO-8859-1";
} else if (file.getName().toLowerCase().endsWith(".metadata.xml")) {
_encoding = "UTF-8";
} else {
_encoding = new WGADesignStructureHelper(((IFileEditorInput) element).getFile()).determineDesignEncoding();
}
return super.createDocument(element);
} else {
throw new CoreException(new Status(Status.ERROR, Plugin.PLUGIN_ID, "Unsupported editorinput."));
}
} else {
throw new CoreException(new Status(Status.ERROR, Plugin.PLUGIN_ID, "Unsupported editorinput. Please import files into an eclipse project first."));
}
}
@Override
protected String getPersistedEncoding(Object element) {
return _encoding;
}
@Override
protected void cacheEncodingState(Object element) throws CoreException {
// ignore
}
@Override
public String getDefaultEncoding() {
return _encoding;
}
@Override
public String getEncoding(Object element) {
return _encoding;
}
public String getEncoding() {
return _encoding;
}
private String retrieveCharsetForNewFile(IFile file, IDocument document, FileInfo info) {
return _encoding;
}
/**
* copied mostly from {@link FileDocumentProvider} bc. getCharsetForNewFile() on {@link FileDocumentProvider} is private !!!
*/
protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException {
if (element instanceof IFileEditorInput) {
IFileEditorInput input= (IFileEditorInput) element;
String encoding= null;
FileInfo info= (FileInfo) getElementInfo(element);
IFile file= input.getFile();
encoding= retrieveCharsetForNewFile(file, document, info);
/*
if (info != null && info.fBOM == IContentDescription.BOM_UTF_16LE && CHARSET_UTF_16.equals(encoding))
encoding= CHARSET_UTF_16LE;*/
Charset charset;
try {
charset= Charset.forName(encoding);
} catch (UnsupportedCharsetException ex) {
String message= "Unsupported encoding '" + encoding + "'.";
IStatus s= new Status(IStatus.ERROR, Plugin.PLUGIN_ID, IStatus.OK, message, ex);
throw new CoreException(s);
} catch (IllegalCharsetNameException ex) {
String message= "Unsupported encoding '" + encoding + "'.";
IStatus s= new Status(IStatus.ERROR, Plugin.PLUGIN_ID, IStatus.OK, message, ex);
throw new CoreException(s);
}
CharsetEncoder encoder= charset.newEncoder();
encoder.onMalformedInput(CodingErrorAction.REPLACE);
encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
InputStream stream;
try {
byte[] bytes;
ByteBuffer byteBuffer= encoder.encode(CharBuffer.wrap(document.get()));
if (byteBuffer.hasArray())
bytes= byteBuffer.array();
else {
bytes= new byte[byteBuffer.limit()];
byteBuffer.get(bytes);
}
stream= new ByteArrayInputStream(bytes, 0, byteBuffer.limit());
} catch (CharacterCodingException ex) {
Assert.isTrue(ex instanceof UnmappableCharacterException);
String message= "Charset mapping failed.";
IStatus s= new Status(IStatus.ERROR, Plugin.PLUGIN_ID, EditorsUI.CHARSET_MAPPING_FAILED, message, null);
throw new CoreException(s);
}
if (file.exists()) {
if (info != null && !overwrite)
checkSynchronizationState(info.fModificationStamp, file);
// inform about the upcoming content change
fireElementStateChanging(element);
try {
file.setContents(stream, overwrite, true, monitor);
} catch (CoreException x) {
// inform about failure
fireElementStateChangeFailed(element);
throw x;
} catch (RuntimeException x) {
// inform about failure
fireElementStateChangeFailed(element);
throw x;
}
// If here, the editor state will be flipped to "not dirty".
// Thus, the state changing flag will be reset.
if (info != null) {
ResourceMarkerAnnotationModel model= (ResourceMarkerAnnotationModel) info.fModel;
if (model != null)
model.updateMarkers(info.fDocument);
info.fModificationStamp= computeModificationStamp(file);
}
} else {
try {
monitor.beginTask("Saving document", 2000);
ContainerCreator creator = new ContainerCreator(file.getWorkspace(), file.getParent().getFullPath());
creator.createContainer(new SubProgressMonitor(monitor, 1000));
file.create(stream, false, new SubProgressMonitor(monitor, 1000));
}
finally {
monitor.done();
}
}
} else {
super.doSaveDocument(monitor, element, document, overwrite);
}
}
}