/* * Copyright 2012 Amazon Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://aws.amazon.com/apache2.0 * * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES * OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and * limitations under the License. */ package com.amazonaws.eclipse.cloudformation.templates.editor; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.editors.text.FileDocumentProvider; import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import com.amazonaws.eclipse.cloudformation.CloudFormationPlugin; import com.amazonaws.eclipse.cloudformation.templates.TemplateArrayNode; import com.amazonaws.eclipse.cloudformation.templates.TemplateNode; import com.amazonaws.eclipse.cloudformation.templates.TemplateObjectNode; public class TemplateEditor extends TextEditor { public interface TemplateDocumentListener { public void templateDocumentChanged(); } public class TemplateDocument extends Document { private ArrayList<TemplateDocumentListener> listeners = new ArrayList<TemplateDocumentListener>(); private TemplateNode model; /** The path from the root to the current position in the Json Document.*/ private List<String> path; public void addTemplateDocumentListener(TemplateDocumentListener listener) { listeners.add(listener); } public void removeTemplateDocumentListener(TemplateDocumentListener listener) { listeners.remove(listener); } public TemplateNode getModel() { return model; } public void setModel(TemplateNode root) { this.model = root; Display.getDefault().asyncExec(new Runnable() { public void run() { for (TemplateDocumentListener listener : listeners) { listener.templateDocumentChanged(); } } }); } public TemplateNode findNode(int documentOffset) { return findNode(documentOffset, model); } private TemplateNode findNode(int documentOffset, TemplateNode node) { if (node.getStartLocation().getCharOffset() > documentOffset) { throw new RuntimeException("Out of bounds in node search"); } if (node.isObject()) { TemplateObjectNode object = (TemplateObjectNode)node; for (Entry<String, TemplateNode> entry : object.getFields()) { entry.getKey(); if (match(documentOffset, entry.getValue())) { return findNode(documentOffset, entry.getValue()); } } } else if (node.isArray()) { TemplateArrayNode array = (TemplateArrayNode)node; for (TemplateNode member : array.getMembers()) { if (match(documentOffset, member)) { return findNode(documentOffset, member); } } } return node; } public List<String> getPath() { return path; } public void setPath(List<String> path) { this.path = path; } } private boolean match(int offset, TemplateNode node) { return offset >= node.getStartLocation().getCharOffset() && offset <= node.getEndLocation().getCharOffset(); } private final class TemplateDocumentProvider extends FileDocumentProvider { @Override protected IDocument createEmptyDocument() { return new TemplateDocument(); } } private IDocumentProvider createDocumentProvider(IEditorInput input) { if (input instanceof IFileEditorInput) { return new TemplateDocumentProvider(); } else if (input instanceof FileStoreEditorInput) { String message = "Unable to open templates from outside the workspace. Copy it into a workspace project first."; IStatus status = new Status(IStatus.ERROR, CloudFormationPlugin.PLUGIN_ID, message); StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG); throw new RuntimeException(message); } else { return new TemplateDocumentProvider(); } } @Override protected void doSetInput(IEditorInput input) throws CoreException { setDocumentProvider(createDocumentProvider(input)); super.doSetInput(input); } private TemplateContentOutlinePage myOutlinePage; public TemplateEditor() { setDocumentProvider(new TemplateDocumentProvider()); setSourceViewerConfiguration(new TemplateSourceViewerConfiguration()); } public TemplateDocument getTemplateDocument() { return (TemplateDocument)this.getDocumentProvider().getDocument(getEditorInput()); } public Object getAdapter(Class required) { if (IContentOutlinePage.class.equals(required)) { if (myOutlinePage == null) { TemplateDocument document = (TemplateDocument)this.getDocumentProvider().getDocument(getEditorInput()); if (document != null) { myOutlinePage = new TemplateContentOutlinePage(document); } } return myOutlinePage; } return super.getAdapter(required); } }