au.org.ala.delta.editor.ui.DirectiveFileEditor.java Source code

Java tutorial

Introduction

Here is the source code for au.org.ala.delta.editor.ui.DirectiveFileEditor.java

Source

/*******************************************************************************
 * Copyright (C) 2011 Atlas of Living Australia
 * All Rights Reserved.
 * 
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 ******************************************************************************/
package au.org.ala.delta.editor.ui;

import au.org.ala.delta.directives.AbstractDirective;
import au.org.ala.delta.directives.ParsingContext;
import au.org.ala.delta.editor.directives.DirectiveFileInfo;
import au.org.ala.delta.editor.directives.DirectiveImportHandlerAdapter;
import au.org.ala.delta.editor.directives.DirectivesFileExporter;
import au.org.ala.delta.editor.directives.DirectivesFileImporter;
import au.org.ala.delta.editor.directives.ImportContext;
import au.org.ala.delta.editor.model.EditorViewModel;
import au.org.ala.delta.editor.slotfile.directive.DirectiveInOutState;
import au.org.ala.delta.editor.slotfile.model.DirectiveFile;
import au.org.ala.delta.editor.ui.util.MessageDialogHelper;
import au.org.ala.delta.editor.ui.validator.TextComponentValidator;
import au.org.ala.delta.editor.ui.validator.ValidationResult;
import au.org.ala.delta.editor.ui.validator.Validator;
import au.org.ala.delta.ui.codeeditor.CodeEditor;
import au.org.ala.delta.ui.codeeditor.CodeTextArea;
import org.apache.commons.lang.StringUtils;
import org.jdesktop.application.Action;
import org.jdesktop.application.Application;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.StringReader;
import java.text.ParseException;
import java.util.List;

/**
 * Provides a user interface that allows directive files to be edited.
 */
public class DirectiveFileEditor extends AbstractDeltaView {

    private static final long serialVersionUID = 9193388605723396077L;

    /** Contains the directive file are editing */
    private EditorViewModel _model;

    private ActionMap _actions;

    private CodeEditor directivesEditor;

    private String originalText;

    private MessageDialogHelper _messageHelper;

    public DirectiveFileEditor(EditorViewModel model) {
        super();
        setName("DirectiveFileEditor");
        _model = model;
        _actions = Application.getInstance().getContext().getActionMap(this);
        _messageHelper = new MessageDialogHelper();
        createUI();
        addEventHandlers();
        updateGUI();
    }

    private void addEventHandlers() {
        javax.swing.Action applyChanges = _actions.get("applyChanges");
        directivesEditor.addToolbarButton(applyChanges, "saveDirectiveFile");
        directivesEditor.getTextArea().getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void removeUpdate(DocumentEvent e) {
                enableSave();
            }

            @Override
            public void insertUpdate(DocumentEvent e) {
                enableSave();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                enableSave();
            }
        });
    }

    private void enableSave() {
        _actions.get("applyChanges").setEnabled(true);
    }

    private void disableSave() {
        _actions.get("applyChanges").setEnabled(false);
    }

    private void createUI() {
        directivesEditor = new CodeEditor(getMimeType());
        directivesEditor.getTextArea().setEOLMarkersPainted(false);
        getContentPane().add(directivesEditor, BorderLayout.CENTER);
    }

    private String getMimeType() {
        DirectiveFile file = _model.getSelectedDirectiveFile();
        String mimeType;
        switch (file.getType()) {
        case CONFOR:
            mimeType = "text/confor";
            break;
        default:
            mimeType = "text/plain";
            break;
        }
        return mimeType;
    }

    private void updateGUI() {
        DirectiveFile file = _model.getSelectedDirectiveFile();
        DirectiveInOutState state = new DirectiveInOutState(_model);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        PrintStream p = new PrintStream(out);
        state.setPrintStream(p);

        DirectivesFileExporter exporter = new DirectivesFileExporter();
        exporter.writeDirectivesFile(file, state);

        if (file.isCharsFile() || file.isItemsFile() || file.isSpecsFile()) {
            directivesEditor.getTextArea().setEditable(false);
        }
        originalText = new String(out.toByteArray());
        directivesEditor.setText(originalText);
        disableSave();
    }

    @Override
    public String getViewTitle() {
        return _model.getSelectedDirectiveFile().getShortFileName() + " - %s";
    }

    @Override
    public boolean canClose() {
        if (originalText.equals(getText())) {
            return true;
        }
        int result = _messageHelper.promtForSaveBeforeClosing();
        if (result == JOptionPane.CANCEL_OPTION) {
            return false;
        } else if (result == JOptionPane.OK_OPTION) {
            applyChanges();
        }
        return true;
    }

    @Action
    public void applyChanges() {
        new CodeEditorValidator(new ImportErrorHandler()).verify(directivesEditor.getTextArea());
    }

    @Override
    public boolean editsValid() {
        return true;
    }

    private String getText() {
        return directivesEditor.getTextArea().getText();
    }

    class ImportErrorHandler extends DirectiveImportHandlerAdapter implements Validator {

        private ValidationResult _result = ValidationResult.success();

        /**
         * Validate the supplied object and return an instance of ValidationResult.
         * @param toValidate the object to validate.
         * @return results of the validation.
         */
        public ValidationResult validate(Object toValidate) {
            ImportContext context = new ImportContext(_model);
            DirectivesFileImporter importer = new DirectivesFileImporter(_model, context);

            String text = getText();
            DirectiveFile file = _model.getSelectedDirectiveFile();
            DirectiveFileInfo fileInfo = new DirectiveFileInfo(file);
            boolean success = importer.importDirectivesFile(fileInfo, new StringReader(text), this);
            if (success) {
                updateGUI();
            }
            return _result;
        }

        @Override
        public void handleUnrecognizedDirective(ImportContext context, List<String> controlWords) {
            String directive = StringUtils.join(controlWords.toArray(), ' ');

            int location = getText().indexOf(directive);
            if (location >= 0) {
                _result = ValidationResult.error("UNRECOGNISED_DIRECTIVE", location);
            } else {
                _result = ValidationResult.error("UNRECOGNISED_DIRECTIVE");
            }

            _result.setMessageArgs(directive);
        }

        @Override
        public void handleDirectiveProcessingException(ImportContext context, AbstractDirective<ImportContext> d,
                Exception ex) {
            if (ex instanceof ParseException) {
                int location = directiveIndex(context);
                ParseException pe = (ParseException) ex;

                location += pe.getErrorOffset();
                _result = ValidationResult.error("DIRECTIVE_PARSE_ERROR", location);
                _result.setMessageArgs(ex.getMessage());
            }
        }

        private int directiveIndex(ImportContext context) {
            ParsingContext pc = context.getCurrentParsingContext();
            int line = (int) pc.getCurrentDirectiveStartLine();
            String text = getText();
            int lineCount = 1;
            int index = 0;
            while (lineCount < line) {
                index = text.indexOf('\n', index + 1);
                lineCount++;
            }
            long offset = index + pc.getDirectiveEndOffset() + 1;
            return (int) offset;
        }

    }

    class CodeEditorValidator extends TextComponentValidator {
        public CodeEditorValidator(Validator validator) {
            super(validator);
        }

        @Override
        public boolean verify(JComponent component) {
            return validate(component);
        }

        public Object getValueToValidate(JComponent component) {
            return getText();
        }

        protected void updateTextStyles(JComponent component, ValidationResult validationResult) {
            CodeTextArea textArea = (CodeTextArea) component;
            if (!validationResult.isValid()) {
                int pos = validationResult.getInvalidCharacterPosition();

                if (pos >= 0) {
                    String text = getText();
                    int nextSpace = text.indexOf(' ', pos);
                    if (nextSpace < 0) {
                        nextSpace = text.length() - 1;
                    }
                    int nextNewline = text.indexOf('\n', pos);
                    if (nextNewline < 0) {
                        nextNewline = text.length() - 1;
                    }

                    textArea.select(Math.max(pos, 0), Math.min(nextSpace, nextNewline));
                }
            }
        }
    }

}