ch.uzh.ifi.attempto.aceview.ui.view.ACESnippetEditorViewComponent.java Source code

Java tutorial

Introduction

Here is the source code for ch.uzh.ifi.attempto.aceview.ui.view.ACESnippetEditorViewComponent.java

Source

/*
 * This file is part of ACE View.
 * Copyright 2008-2009, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
 *
 * ACE View is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * ACE View is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with ACE View.
 * If not, see http://www.gnu.org/licenses/.
 */

package ch.uzh.ifi.attempto.aceview.ui.view;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.net.URI;
import java.util.List;
import java.util.Map.Entry;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;

import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.VerticalLayout;
import org.protege.editor.core.ui.util.Icons;
import org.protege.editor.owl.OWLEditorKit;
import org.protege.editor.owl.model.util.OWLAxiomInstance;
import org.protege.editor.owl.ui.UIHelper;
import org.protege.editor.owl.ui.renderer.OWLRendererPreferences;
import org.semanticweb.owl.model.OWLAxiom;
import org.semanticweb.owl.model.OWLEntity;
import org.semanticweb.owl.model.OWLLogicalAxiom;

import com.google.common.collect.Multimap;

import ch.uzh.ifi.attempto.ace.ACESentence;
import ch.uzh.ifi.attempto.ace.ACESplitter;
import ch.uzh.ifi.attempto.aceview.ACESnippet;
import ch.uzh.ifi.attempto.aceview.ACESnippetImpl;
import ch.uzh.ifi.attempto.aceview.ACEText;
import ch.uzh.ifi.attempto.aceview.ACETextManager;
import ch.uzh.ifi.attempto.aceview.model.event.ACETextChangeEvent;
import ch.uzh.ifi.attempto.aceview.model.event.ACETextManagerListener;
import ch.uzh.ifi.attempto.aceview.model.event.EventType;
import ch.uzh.ifi.attempto.aceview.ui.ACESnippetEditor;
import ch.uzh.ifi.attempto.aceview.ui.AxiomAnnotationPanel;
import ch.uzh.ifi.attempto.aceview.ui.Colors;
import ch.uzh.ifi.attempto.aceview.ui.util.ComponentFactory;
import ch.uzh.ifi.attempto.aceview.util.SnippetRenderer;

/**
 * <p>This view component allows one to view and edit the selected snippet.</p>
 * 
 * <p>The editor auto-completes ACE words (if the TAB-key is pressed). The auto-completion
 * is done on the basis of the wordforms in the active ACE text's lexicon.</p>
 *
 * <p>Three buttons enable the active ACE text to be modified:</p>
 * 
 * <ul>
 * <li><code>Add as new</code>: adds the selected snippet to the text (if it is not there already)</li>
 * <li><code>Update</code>: updates the selected snippet (if it is in the text)</li>
 * <li><code>Delete</code>: deletes the selected snippet (if it is in the text)</li>
 * </ul>
 * 
 * <p>In addition, there are two buttons:</p>
 * 
 * <ul>
 * <li>The <code>Annotate</code>-button allows one to annotate the
 * snippet, i.e. add an axiom annotation axiom (that annotates the snippet's axiom)
 * into the underlying ontology of the active ACE text.</li>
 * <li>The <code>Why?</code>-button triggers the "Why? event", asking the reasoner to
 * explain the selected snippet on the basis of the active ACE text.</li>
 * </ul>
 * 
 * @author Kaarel Kaljurand
 */
public class ACESnippetEditorViewComponent extends AbstractACESnippetSelectionViewComponent {

    private static final Logger logger = Logger.getLogger(ACESnippetEditorViewComponent.class);

    private final OWLRendererPreferences owlRendererPreferences = OWLRendererPreferences.getInstance();

    private final int PADDING = 2;

    private JButton buttonNew;
    private JButton buttonUpdate;
    private JButton buttonDelete;
    private JButton buttonWhy;
    private JButton buttonAnnotate;

    private ACESnippetEditor snippetEditor;

    private JLabel labelMessage;

    private final Icon iconError = Icons.getIcon("error.png");
    private final Icon iconWarning = Icons.getIcon("warning.png");

    private AxiomAnnotationPanel axiomAnnotationPanel;

    private final ACETextManagerListener aceTextManagerListener = new ACETextManagerListener() {
        public void handleChange(ACETextChangeEvent event) {
            // We update the auto-completer if the lexicon changed,
            // or an ACE text was created, or the active ACE text changed.
            // TODO: maybe we should make sure that the lexicon change is
            // the change of the active ACE text's lexicon.
            if (event.isType(EventType.ACTIVE_ACETEXT_CHANGED) || event.isType(EventType.ACETEXT_CREATED)
                    || event.isType(EventType.ACELEXICON_CHANGED)) {
                snippetEditor.setAutocompleter(ACETextManager.getActiveACELexicon().getAutocompleter());
            }
        }
    };

    @Override
    protected void initialiseOWLView() throws Exception {
        snippetEditor = new ACESnippetEditor(4, 50);
        snippetEditor.setToolTipText("Selected ACE snippet.");
        snippetEditor.setAutocompleter(ACETextManager.getActiveACELexicon().getAutocompleter());

        JScrollPane scrollpaneAce = new JScrollPane(snippetEditor, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        labelMessage = new JLabel("");
        labelMessage.setFont(labelMessage.getFont().deriveFont(10.0f));
        labelMessage.setBorder(BorderFactory.createEmptyBorder(PADDING, PADDING, PADDING, PADDING));
        labelMessage.setPreferredSize(new Dimension(labelMessage.getPreferredSize().width, 40));

        buttonNew = ComponentFactory.makeButton("Add as new");
        buttonNew.setMnemonic(KeyEvent.VK_ENTER);
        buttonNew.setToolTipText("Create a new snippet on the basis of the text in the editor window.");

        buttonNew.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                List<ACESentence> sentences = ACESplitter.getSentences(snippetEditor.getText());
                if (sentences.isEmpty()) {
                    displayWarningMessage("Not added. There are no sentences.");
                } else {
                    ACEText<OWLEntity, OWLLogicalAxiom> acetext = ACETextManager.getActiveACEText();
                    ACESnippet oldSnippet = acetext.find(sentences);
                    if (oldSnippet == null) {
                        URI name = ACETextManager.getActiveACETextURI();
                        ACESnippetImpl newSnippet = new ACESnippetImpl(name, sentences);
                        ACETextManager.addSnippet(newSnippet);
                        ACETextManager.setSelectedSnippet(newSnippet);
                    } else {
                        displayWarningMessage("Not added. These sentences are already in the text.");
                    }
                }
                snippetEditor.requestFocusInWindow(); // Get focus back
            }
        });

        buttonUpdate = ComponentFactory.makeButton("Update");
        buttonUpdate.setToolTipText("Update the selected snippet on the basis of the text in the editor window.");

        buttonUpdate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                ACESnippet selectedSnippet = ACETextManager.getSelectedSnippet();
                if (selectedSnippet != null) {
                    List<ACESentence> sentences = ACESplitter.getSentences(snippetEditor.getText());
                    if (sentences.isEmpty()) {
                        deleteSnippet(selectedSnippet);
                    } else {
                        ACEText<OWLEntity, OWLLogicalAxiom> acetext = ACETextManager.getActiveACEText();
                        ACESnippet oldSnippet = acetext.find(sentences);
                        if (oldSnippet == null) {
                            ACETextManager.updateSnippet(acetext.indexOf(selectedSnippet), selectedSnippet,
                                    sentences);
                        } else {
                            displayWarningMessage(
                                    "Selected snippet <b>not</b> updated. These sentences are already in the text.");
                        }
                    }
                    snippetEditor.requestFocusInWindow(); // Get focus back
                }
            }
        });

        buttonDelete = ComponentFactory.makeButton("Delete");
        buttonDelete.setToolTipText("Delete the selected snippet from the ACE text.");
        buttonDelete.setMnemonic(KeyEvent.VK_BACK_SPACE);

        buttonDelete.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                ACESnippet selectedSnippet = ACETextManager.getSelectedSnippet();
                if (selectedSnippet != null) {
                    deleteSnippet(selectedSnippet);
                    snippetEditor.requestFocusInWindow(); // Get focus back
                }
            }
        });

        buttonWhy = ComponentFactory.makeButton("Why?");
        buttonWhy.setToolTipText("Why is the selected snippet entailed?");

        buttonWhy.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                ACESnippet selectedSnippet = ACETextManager.getSelectedSnippet();
                if (selectedSnippet != null) {
                    ACETextManager.setWhySnippet(selectedSnippet);
                }
            }
        });

        buttonAnnotate = ComponentFactory.makeButton("Annotate");
        buttonAnnotate.setToolTipText("Annotate the selected snippet.");

        buttonAnnotate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                ACESnippet selectedSnippet = ACETextManager.getSelectedSnippet();
                if (selectedSnippet != null) {
                    OWLLogicalAxiom ax = selectedSnippet.getAxiom();
                    if (ax != null) {
                        invokeAxiomAnnotationHandler(ax);
                    }
                }
            }
        });

        JXPanel boxButtons = new JXPanel();
        boxButtons.setLayout(new VerticalLayout());
        boxButtons.add(buttonNew);
        boxButtons.add(buttonUpdate);
        boxButtons.add(buttonDelete);
        boxButtons.add(buttonAnnotate);
        boxButtons.add(buttonWhy);

        // Editor panel
        JPanel panelEditor = new JPanel(new BorderLayout());
        panelEditor.add(scrollpaneAce, BorderLayout.CENTER);
        panelEditor.add(labelMessage, BorderLayout.SOUTH);

        // Editor and buttons box
        Box boxEditor = new Box(BoxLayout.X_AXIS);
        boxEditor.setBorder(ComponentFactory.makeBorder());
        boxEditor.add(panelEditor);
        boxEditor.add(boxButtons);

        setLayout(new BorderLayout());
        add(boxEditor);
        refreshComponent();
        resetUI();
        ACETextManager.addListener(aceTextManagerListener);
        ACETextManager.addSnippetListener(getACESnippetListener());
        getOWLWorkspace().getOWLSelectionModel().addListener(getOWLSelectionModelListener());
    }

    private void refreshComponent() {
        if (snippetEditor != null) {
            snippetEditor.setFont(owlRendererPreferences.getFont());
        }
    }

    @Override
    protected void disposeOWLView() {
        if (axiomAnnotationPanel != null) {
            axiomAnnotationPanel.dispose();
        }
        getOWLWorkspace().getOWLSelectionModel().removeListener(getOWLSelectionModelListener());
        ACETextManager.removeListener(aceTextManagerListener);
        ACETextManager.removeSnippetListener(getACESnippetListener());
    }

    /**
     * Resets the snippet editor UI.
     */
    private void resetUI() {
        // Header
        getView().setHeaderText("(No snippet selected.)");

        // Snippet editor text-area
        snippetEditor.setText("");
        snippetEditor.getHighlighter().removeAllHighlights();
        clearMessage();

        // Snippet editor buttons
        buttonNew.setEnabled(true);
        buttonUpdate.setEnabled(false);
        buttonDelete.setEnabled(false);
        buttonWhy.setEnabled(false);
        buttonAnnotate.setEnabled(false);
    }

    @Override
    protected void displaySnippet(ACESnippet snippet) {
        if (!isSynchronizing())
            return;

        if (snippet == null) {
            resetUI();
            return;
        }

        getView().setHeaderText(snippet.toString());

        SnippetRenderer snippetRenderer = new SnippetRenderer(snippet);
        snippetEditor.setText(snippetRenderer.getRendering());
        snippetEditor.getHighlighter().removeAllHighlights();
        // Snippet editor buttons
        buttonNew.setEnabled(true);

        if (ACETextManager.getActiveACEText().contains(snippet)) {
            buttonUpdate.setEnabled(true);
            buttonDelete.setEnabled(true);
            if (snippet.getAxiom() == null) {
                buttonAnnotate.setEnabled(false);
            } else {
                buttonAnnotate.setEnabled(true);
            }
        } else {
            buttonUpdate.setEnabled(false);
            buttonDelete.setEnabled(false);
            buttonAnnotate.setEnabled(false);
        }

        if (snippet.isQuestion() || !snippet.hasAxioms()) {
            buttonWhy.setEnabled(false);
        } else {
            buttonWhy.setEnabled(true);
        }

        if (snippet.hasACEErrors()) {
            displayErrorMessage("The snippet contains ACE syntax errors.");
            Multimap<Integer, Integer> hlCoords = snippetRenderer.getSpans();

            for (Entry<Integer, Integer> entry : hlCoords.entries()) {
                try {
                    logger.info("Added highlighter: coords: " + entry.getKey() + " " + entry.getValue());
                    snippetEditor.getHighlighter().addHighlight(entry.getKey(), entry.getValue(),
                            new DefaultHighlighter.DefaultHighlightPainter(Colors.ERROR_COLOR));
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }
            }
        } else if (!snippet.hasAxioms()) {
            displayErrorMessage("The snippet contains no ACE syntax errors, but cannot be expressed in OWL/SWRL.");
        } else {
            clearMessage();
        }
    }

    private void displayErrorMessage(String message) {
        displayMessage(iconError, "<html>" + message + "</html>");
    }

    private void displayWarningMessage(String message) {
        displayMessage(iconWarning, "<html>" + message + "</html>");
    }

    private void clearMessage() {
        displayMessage(null, "");
    }

    private void displayMessage(Icon icon, String text) {
        labelMessage.setIcon(icon);
        labelMessage.setText(text);
        labelMessage.validate();
    }

    private void invokeAxiomAnnotationHandler(OWLAxiom ax) {
        OWLEditorKit editorKit = getOWLEditorKit();
        if (axiomAnnotationPanel == null) {
            axiomAnnotationPanel = new AxiomAnnotationPanel(editorKit);
        }
        // TODO: BUG: think about it, we should get the ontology that contains the axiom,
        // not the active ontology
        axiomAnnotationPanel.setAxiom(new OWLAxiomInstance(ax, getOWLModelManager().getActiveOntology()));
        new UIHelper(editorKit).showDialog("Annotations", axiomAnnotationPanel, JOptionPane.CLOSED_OPTION);
    }

    /**
     * <p>Convenience method the delete a snippet and
     * update the GUI.</p>
     * 
     * @param snippet ACE snippet
     */
    private void deleteSnippet(ACESnippet snippet) {
        ACETextManager.removeSnippet(snippet);
        ACETextManager.resetSelectedSnippet();
        displayWarningMessage("Selected snippet deleted.");
    }
}