com.boothen.jsonedit.core.editors.JsonTextEditor.java Source code

Java tutorial

Introduction

Here is the source code for com.boothen.jsonedit.core.editors.JsonTextEditor.java

Source

/*******************************************************************************
 * Copyright 2014 Boothen Technology Ltd.
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *   
 * https://eclipse.org/org/documents/epl-v10.html
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License 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.boothen.jsonedit.core.editors;

import java.util.HashMap;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.DefaultCharacterPairMatcher;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.jface.text.source.projection.ProjectionSupport;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

import com.boothen.jsonedit.core.editors.listeners.PlatformPreferenceListener;
import com.boothen.jsonedit.core.handlers.FormatTextHandler;
import com.boothen.jsonedit.core.model.jsonnode.JsonNode;
import com.boothen.jsonedit.outline.JsonContentOutlinePage;
import com.boothen.jsonedit.preferences.JsonPreferenceStore;

/**
 * JsonTextEditor is the TextEditor instance used by the plugin.
 *
 * @author Matt Garner
 *
 */
public class JsonTextEditor extends TextEditor {

    private final static char[] PAIRS = { '{', '}', '[', ']' };

    private DefaultCharacterPairMatcher pairsMatcher = new DefaultCharacterPairMatcher(PAIRS);
    private JsonSourceViewerConfiguration viewerConfiguration;
    private JsonContentOutlinePage fOutlinePage;
    private JsonPreferenceStore jsonPreferenceStore;
    private PlatformPreferenceListener platformPreferenceListener;

    private ProjectionAnnotationModel annotationModel;
    private ProjectionAnnotation[] oldAnnotations;
    private boolean[] annotationCollapsedState;
    private boolean restoreCursorLocation = false;
    private int nodePositionOffset = 0;
    private int nodePosition = 0;
    private List<JsonNode> jsonNodes;

    public JsonTextEditor() {
        super();
        jsonPreferenceStore = new JsonPreferenceStore();
        viewerConfiguration = new JsonSourceViewerConfiguration(this, jsonPreferenceStore);
        setSourceViewerConfiguration(viewerConfiguration);
        //      setDocumentProvider(new JsonDocumentProvider());
    }

    @Override
    protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
        support.setCharacterPairMatcher(pairsMatcher);
        support.setMatchingCharacterPainterPreferenceKeys(JsonPreferenceStore.EDITOR_MATCHING_BRACKETS,
                JsonPreferenceStore.EDITOR_MATCHING_BRACKETS_COLOR);
        super.configureSourceViewerDecorationSupport(support);
    }

    @Override
    protected void initializeEditor() {
        super.initializeEditor();

        setEditorContextMenuId("#JsonTextEditorContext"); //$NON-NLS-1$
        setRulerContextMenuId("#JsonTextRulerContext"); //$NON-NLS-1$
        setPreferenceStore(JsonPreferenceStore.getChainedPreferenceStore());

    }

    @Override
    public void dispose() {
        if (fOutlinePage != null)
            fOutlinePage.setInput(null);

        if (pairsMatcher != null) {
            pairsMatcher.dispose();
            pairsMatcher = null;
        }

        if (platformPreferenceListener != null) {
            platformPreferenceListener.removePreferenceChangeListener();
        }

        super.dispose();
    }

    @Override
    public void doRevertToSaved() {
        super.doRevertToSaved();
        if (fOutlinePage != null)
            fOutlinePage.update();
    }

    @Override
    public void doSave(IProgressMonitor monitor) {
        doAutoFormatOnSave();
        super.doSave(monitor);
        if (fOutlinePage != null)
            fOutlinePage.update();
    }

    /** The <code>JavaEditor</code> implementation of this
     * <code>AbstractTextEditor</code> method performs any extra
     * save as behavior required by the java editor.
     */
    @Override
    public void doSaveAs() {
        doAutoFormatOnSave();
        super.doSaveAs();
        if (fOutlinePage != null)
            fOutlinePage.update();
    }

    private void doAutoFormatOnSave() {
        IPreferenceStore store = getPreferenceStore();
        boolean autoFormatOnSave = store.getBoolean(JsonPreferenceStore.AUTO_FORMAT_ON_SAVE);
        if (autoFormatOnSave) {
            boolean spaces = store.getBoolean(JsonPreferenceStore.SPACES_FOR_TABS);
            int numSpaces = store.getInt(JsonPreferenceStore.NUM_SPACES);
            FormatTextHandler.formatText(this, spaces, numSpaces);
        }
    }

    /** The <code>JavaEditor</code> implementation of this
     * <code>AbstractTextEditor</code> method performs sets the
     * input of the outline page after AbstractTextEditor has set input.
     *
     * @param input the editor input
     * @throws CoreException in case the input can not be set
     */
    @Override
    public void doSetInput(IEditorInput input) throws CoreException {
        super.doSetInput(input);
        if (fOutlinePage != null)
            fOutlinePage.setInput(input);
    }

    /** The <code>JavaEditor</code> implementation of this
     * <code>AbstractTextEditor</code> method performs gets
     * the java content outline page if request is for a an
     * outline page.
     *
     * @param required the required type
     * @return an adapter for the required type or <code>null</code>
     */
    @Override
    public Object getAdapter(@SuppressWarnings("rawtypes") Class required) {
        if (IContentOutlinePage.class.equals(required)) {
            if (fOutlinePage == null) {
                fOutlinePage = new JsonContentOutlinePage(getDocumentProvider(), this);
                if (getEditorInput() != null)
                    fOutlinePage.setInput(getEditorInput());
            }
            return fOutlinePage;
        }

        return super.getAdapter(required);
    }

    @Override
    public void createPartControl(Composite parent) {

        super.createPartControl(parent);

        ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
        ProjectionSupport projectionSupport = new ProjectionSupport(viewer, getAnnotationAccess(),
                getSharedColors());
        projectionSupport.install();

        //turn projection mode on
        viewer.doOperation(ProjectionViewer.TOGGLE);

        annotationModel = viewer.getProjectionAnnotationModel();

        SourceViewerDecorationSupport support = getSourceViewerDecorationSupport(viewer);
        support.install(getPreferenceStore());

        IFile file = (IFile) getEditorInput().getAdapter(IFile.class);
        platformPreferenceListener = new PlatformPreferenceListener(viewerConfiguration, jsonPreferenceStore);
        platformPreferenceListener.setPreferenceChangeListener(file);

    }

    @Override
    protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {

        fAnnotationAccess = getAnnotationAccess();
        fOverviewRuler = createOverviewRuler(getSharedColors());

        ISourceViewer viewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(),
                styles);
        // ensure decoration support has been created and configured.
        getSourceViewerDecorationSupport(viewer);
        return viewer;
    }

    @Override
    protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
        ((JsonSourceViewerConfiguration) viewerConfiguration).handlePreferenceStoreChanged();
        super.handlePreferenceStoreChanged(event);
    }

    public void updateFoldingStructure(List<Position> positions) {
        ProjectionAnnotation[] annotations = new ProjectionAnnotation[positions.size()];

        //this will hold the new annotations along
        //with their corresponding positions
        HashMap<ProjectionAnnotation, Position> newAnnotations = new HashMap<ProjectionAnnotation, Position>();

        for (int i = 0; i < positions.size(); i++) {
            ProjectionAnnotation annotation = new ProjectionAnnotation();
            newAnnotations.put(annotation, positions.get(i));
            annotations[i] = annotation;
            if (annotationCollapsedState != null && annotationCollapsedState.length > i
                    && annotationCollapsedState[i]) {
                annotation.markCollapsed();
            }
        }

        annotationModel.modifyAnnotations(oldAnnotations, newAnnotations, null);
        oldAnnotations = annotations;
    }

    public JsonContentOutlinePage getFOutlinePage() {
        return fOutlinePage;
    }

    public void updateContentOutlinePage(List<JsonNode> jsonNodes) {
        this.jsonNodes = jsonNodes;
        if (fOutlinePage != null) {
            fOutlinePage.setJsonNodes(jsonNodes);
        }

        restoreTextLocation();
    }

    public void storeOutlineState() {
        if (oldAnnotations != null) {
            annotationCollapsedState = new boolean[oldAnnotations.length];
            for (int i = 0; i < oldAnnotations.length; i++) {
                annotationCollapsedState[i] = oldAnnotations[i].isCollapsed();
            }
        }
    }

    public void storeTextLocation() {

        ITextSelection iTextSelection = (ITextSelection) this.getSite().getSelectionProvider().getSelection();
        int textLocation = iTextSelection.getOffset();
        if (jsonNodes != null) {
            for (int i = 0; i < jsonNodes.size(); i++) {
                JsonNode jsonNode = jsonNodes.get(i);
                if (jsonNode.containsLocation(textLocation)) {
                    nodePosition = i;
                    nodePositionOffset = textLocation - jsonNode.getStart();
                    break;
                }
            }
        }

        restoreCursorLocation = true;
    }

    public void restoreTextLocation() {

        if (!restoreCursorLocation) {
            return;
        }

        restoreCursorLocation = false;

        ITextOperationTarget target = (ITextOperationTarget) this.getAdapter(ITextOperationTarget.class);
        if (!(target instanceof ITextViewer)) {
            return;
        }
        ITextViewer textViewer = (ITextViewer) target;
        if (jsonNodes != null && jsonNodes.size() > nodePosition) {
            JsonNode node = jsonNodes.get(nodePosition);
            if (node != null) {
                int textLocation = node.getStart() + nodePositionOffset;
                textViewer.getTextWidget().setSelection(textLocation);
            }
        }
    }

    public void updateTabWidth(int tabWidth) {
        getSourceViewer().getTextWidget().setTabs(tabWidth);
    }
}