+package org.simantics.graphfile.ui.editor;
+
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.source.AnnotationModel;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.ui.texteditor.AbstractDocumentProvider;
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.UniqueRead;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.document.DocumentResource;
+import org.simantics.graphfile.ontology.GraphFileResource;
+import org.simantics.ui.workbench.ResourceEditorInput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PlainTextEditorDocumentProvider extends AbstractDocumentProvider {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PlainTextEditor.class);
+
+ protected String currentText;
+
+ @Override
+ protected IDocument createDocument(Object element) throws CoreException {
+ ResourceEditorInput input = (ResourceEditorInput)element;
+ final Resource resource = input.getResource();
+ try {
+ return Simantics.getSession().syncRequest(new UniqueRead<Document>() {
+ @Override
+ public Document perform(ReadGraph graph) throws DatabaseException {
+
+ GraphFileResource GF = GraphFileResource.getInstance(graph);
+ DocumentResource DOC = DocumentResource.getInstance(graph);
+ if (!graph.isInstanceOf(resource, DOC.FileDocument))
+ throw new DatabaseException("Invalid input resource for PlainTextEditor: " + NameUtils.getSafeName(graph, resource));
+
+ byte[] bytes = graph.getPossibleRelatedValue(resource, GF.HasFiledata, Bindings.BYTE_ARRAY);
+
+ currentText = bytes != null ? new String(bytes, StandardCharsets.UTF_8) : "";
+
+ return new Document(currentText);
+
+ }
+ });
+ } catch (DatabaseException e) {
+ StringWriter sw = new StringWriter();
+ LOGGER.error("Failed to create document", e);
+ return new Document(sw.toString());
+ }
+ }
+
+ @Override
+ protected IAnnotationModel createAnnotationModel(Object element)
+ throws CoreException {
+ return new AnnotationModel();
+ }
+
+ @Override
+ protected void doSaveDocument(IProgressMonitor monitor, Object element,
+ IDocument document, boolean overwrite) throws CoreException {
+ ResourceEditorInput input = (ResourceEditorInput)element;
+ final Resource resource = input.getResource();
+ final String text = document.get();
+ currentText = text;
+ Simantics.getSession().asyncRequest(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ graph.markUndoPoint();
+ GraphFileResource GF = GraphFileResource.getInstance(graph);
+ graph.claimLiteral(resource, GF.HasFiledata, text.getBytes(StandardCharsets.UTF_8));
+ graph.claimLiteral(resource, GF.LastModified, System.currentTimeMillis());
+ }
+ });
+ }
+
+ @Override
+ protected IRunnableContext getOperationRunner(IProgressMonitor monitor) {
+ return null;
+ }
+
+ @Override
+ public boolean isModifiable(Object element) {
+ return true;
+ }
+
+ @Override
+ public boolean isReadOnly(Object element) {
+ return false;
+ }
+
+ @Override
+ public boolean canSaveDocument(Object element) {
+ return !getDocument(element).get().equals(currentText);
+ }
+
+}