Package org.openquark.gems.client

Source Code of org.openquark.gems.client.NavigatorAdapter

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Business Objects nor the names of its contributors
*       may be used to endorse or promote products derived from this software
*       without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/


/*
* NavigatorAdapter.java
* Creation date: Jul 23, 2003
* By: Frank Worsley
*/
package org.openquark.gems.client;

import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.event.UndoableEditListener;
import javax.swing.tree.TreeNode;
import javax.swing.undo.StateEdit;
import javax.swing.undo.StateEditable;

import org.openquark.cal.compiler.ScopedEntity;
import org.openquark.cal.compiler.TypeChecker;
import org.openquark.cal.metadata.ArgumentMetadata;
import org.openquark.cal.metadata.CALFeatureMetadata;
import org.openquark.cal.metadata.FunctionalAgentMetadata;
import org.openquark.cal.services.GemEntity;
import org.openquark.cal.services.MetaModule;
import org.openquark.cal.services.Perspective;
import org.openquark.gems.client.Gem.PartInput;
import org.openquark.gems.client.explorer.TableTopExplorer;
import org.openquark.gems.client.navigator.NavAddress;
import org.openquark.gems.client.navigator.NavAddressHelper;
import org.openquark.gems.client.navigator.NavFrame;
import org.openquark.gems.client.navigator.NavFrameOwner;
import org.openquark.gems.client.navigator.NavAddress.NavAddressMethod;
import org.openquark.gems.client.utilities.ExtendedUndoableEditSupport;
import org.openquark.util.Pair;


/**
* The GemCutter's implementation of the NavFrameOwner interface. This class is basically
* a thin wrapper around the NavFrame class. It delegates to an instance of NavFrame for all
* functionality and simply adds undo support on top of NavFrame.
*
* @author Frank Worsley
*/
class NavigatorAdapter implements NavFrameOwner {

    /**
     * Implements a state editable for metadata objects.
     * @author Frank Worsley
     */
    private class MetadataStateEditable implements StateEditable {

        /** The metadata key in the state maps. */
        private static final String METADATA_STATE_KEY = "MetadataStateKey";

        /** The address of the metadata object this editable is for. */
        private final NavAddress address;

        /**
         * Constructs a new state editable for the given metadata object.
         * @param address the address of the metadata object
         */
        public MetadataStateEditable(NavAddress address) {

            if (address == null) {
                throw new NullPointerException();
            }
       
            this.address = address;
        }

        /**
         * @see javax.swing.undo.StateEditable#storeState(java.util.Hashtable)
         */
        public void storeState(Hashtable<Object, Object> state) {
            CALFeatureMetadata metadata = NavAddressHelper.getMetadata(NavigatorAdapter.this, address);           
            state.put(getKey(), metadata);
        }

        /**
         * @see javax.swing.undo.StateEditable#restoreState(java.util.Hashtable)
         */
        public void restoreState(Hashtable<?, ?> state) {

            CALFeatureMetadata savedState = (CALFeatureMetadata) state.get(getKey());
       
            if (savedState != null) {
           
                boolean success = NavAddressHelper.saveMetadata(NavigatorAdapter.this, address, savedState);
               
                if (!success) {
                    throw new IllegalStateException("failed to restore saved metadata state");
                }

                // Update the state edit if the currently edited metadata was changed.
                if (address.equals(currentEditAddress)) {
                    stateEdit = new StateEdit(new MetadataStateEditable(address));
                }

                // Check the table top names once the undo completes.
                // We need to do it after the undo so GemGraph checking is enabled again.
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        updateInputNames(address);
                        nameCheckTableTop();
                        navFrame.refreshMetadata(address);
                    }
                });
            }
        }
   
        /**
         * @return the key to use in the state maps for the metadata
         */
        private Object getKey() {
            return new Pair<NavAddress, String>(address, METADATA_STATE_KEY);
        }
    }

   
    /** The undoable edit support for the navigator adapter. */
    private final ExtendedUndoableEditSupport undoableEditSupport;

    /** The GemCutter this adapter is for. */
    private final GemCutter gemCutter;

    /** The navigator frame this adapter is using. */
    private NavFrame navFrame = null;

    /** The state edit for the metadata object being edited. */
    private StateEdit stateEdit = null;
   
    /** The address of the metadata object currently being edited. */
    private NavAddress currentEditAddress = null;

    /**
     * Constructor for a new navigator adapter for a GemCutter.
     * @param gemCutter the GemCutter this adapter is for
     */
    public NavigatorAdapter(GemCutter gemCutter) {
       
        if (gemCutter == null) {
            throw new NullPointerException();
        }
       
        this.gemCutter = gemCutter;
        this.undoableEditSupport = new ExtendedUndoableEditSupport(this);
    }

    /**
     * Add an undoable edit listener.
     * @param listener the listener to add
     */
    public void addUndoableEditListener(UndoableEditListener listener) {
        undoableEditSupport.addUndoableEditListener(listener);
    }
   
    /**
     * Remove an undoable edit listener.
     * @param listener the listener to remove
     */
    public void removeUndoableEditListener(UndoableEditListener listener) {
        undoableEditSupport.removeUndoableEditListener(listener);
    }

    /**
     * @return whether or not the navigator instance if visible on screen
     */
    private boolean navigatorCanView() {
        return navFrame.isVisible() && !navFrame.isEditing();
    }

    /**
     * Refreshed the navigatior tree by reloading the CAL entities from the perspective.
     * This has to be done after a gem is saved so that the new gem shows up in the tree.
     */
    public void refresh() {
       
        if (navFrame == null) {
            navFrame = new NavFrame(this);
        }
       
        navFrame.refreshTree();
    }
   
    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#getParent()
     */
    public JFrame getParent() {
        return gemCutter;
    }

    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#getTypeChecker()
     */
    public TypeChecker getTypeChecker() {
        return gemCutter.getTypeChecker();
    }

    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#getValueRunner()
     */
    public ValueRunner getValueRunner() {
        return gemCutter.getValueRunner();
    }

    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#getPerspective()
     */
    public Perspective getPerspective() {
        return gemCutter.getPerspective();
    }

    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#getCollector(java.lang.String)
     */
    public CollectorGem getCollector(String name) {
        Set<CollectorGem> collectors = gemCutter.getTableTop().getGemGraph().getCollectorsForName(name);
        return (collectors.size() == 0) ? null : collectors.iterator().next();
    }

    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#displayNavigator(boolean)
     */
    public void displayNavigator(boolean newNavigator) {
        navFrame.setVisible(true);
        navFrame.refreshViewer();
        navFrame.requestFocus();
    }

    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#displayMetadata(org.openquark.gems.client.navigator.NavAddress, boolean)
     */
    public void displayMetadata(NavAddress address, boolean newViewer) {
        if (navigatorCanView() || newViewer) {
            navFrame.displayMetadata(address);
        }
    }

    /**
     * Display metadata for the given entity.
     * @param entity the entity to display metadata for
     * @param newViewer true if a new window should be opened
     */
    public void displayMetadata(GemEntity entity, boolean newViewer) {
        displayMetadata(NavAddress.getAddress(entity), newViewer);
    }

    /**
     * Display metadata for the given entity.
     * @param entity the entity to display metadata for
     * @param newViewer true if a new window should be opened
     */
    public void displayMetadata(ScopedEntity entity, boolean newViewer) {
        displayMetadata(NavAddress.getAddress(entity), newViewer);
    }

    /**
     * Display metadata for the given module.
     * @param module the module to display metadata for
     * @param newViewer true if a new window should be opened
     */
    public void displayMetadata(MetaModule module, boolean newViewer) {
        displayMetadata(NavAddress.getAddress(module), newViewer);
    }
   
    /**
     * Display metadata for the given collector.
     * @param collector the collector to display metadata for
     * @param newViewer true if a new window should be opened
     */
    public void displayMetadata(CollectorGem collector, boolean newViewer) {
        displayMetadata(NavAddress.getAddress(collector), newViewer);
    }

    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#editMetadata(org.openquark.gems.client.navigator.NavAddress)
     */
    public void editMetadata(NavAddress address) {
        navFrame.editMetadata(address);
        currentEditAddress = address;
        stateEdit = new StateEdit(new MetadataStateEditable(address));
    }

    /**
     * Edit metadata for the given entity.
     * @param entity the entity to edit metadata for
     */
    public void editMetadata(ScopedEntity entity) {
        editMetadata(NavAddress.getAddress(entity));
    }

    /**
     * Edit metadata for the given module.
     * @param module the module to edit metadata for
     */
    public void editMetadata(MetaModule module) {
        editMetadata(NavAddress.getAddress(module));
    }

    /**
     * Edit metadata for the given collector.
     * @param collector the collector to edit metadata for
     */
    public void editMetadata(CollectorGem collector) {
        editMetadata(NavAddress.getAddress(collector));
    }
   
    /**
     * Edit argument metadata for the given entity.
     * @param entity the entity to edit argument metadata for
     * @param argNum the number of the argument whose metadata to edit
     */
    public void editMetadata(GemEntity entity, int argNum) {
        NavAddress address = NavAddress.getAddress(entity).withParameter(NavAddress.ARGUMENT_PARAMETER, Integer.toString(argNum));
        editMetadata(address);
    }
   
    /**
     * Edit argument metadata for the given collector.
     * @param collector the collector to edit argument metadata for
     * @param argNum the number of the argument whose metadata to edit
     */   
    public void editMetadata(CollectorGem collector, int argNum) {
        NavAddress address = NavAddress.getAddress(collector).withParameter(NavAddress.ARGUMENT_PARAMETER, Integer.toString(argNum));
        editMetadata(address);
    }
   
    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#editComplete(org.openquark.gems.client.navigator.NavAddress)
     */
    public void editComplete(NavAddress address) {

        if (!address.equals(currentEditAddress)) {
            throw new IllegalStateException("address for completed edit does not equal current edit address");
        }
       
        currentEditAddress = null;
        stateEdit = null;
    }
   
    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#metadataChanged(org.openquark.gems.client.navigator.NavAddress)
     */
    public void metadataChanged(NavAddress address) {

        if (!address.equals(currentEditAddress)) {
            throw new IllegalStateException("address for changed edit does not equal current edit address");
        }
       
        stateEdit.end();
       
        undoableEditSupport.beginUpdate();
        undoableEditSupport.setEditName(GemCutter.getResourceString("UndoText_ChangeGemProperties"));
        undoableEditSupport.postEdit(stateEdit);
        undoableEditSupport.endUpdate();

        stateEdit = new StateEdit(new MetadataStateEditable(address));
       
        updateInputNames(address);
        nameCheckTableTop();
       
        navFrame.refreshMetadata(currentEditAddress);
    }
   
    /**
     * Updates the names of any PartInputs affected by the metadata changing for the
     * entity with the given address. Does nothing if no updates are required.
     * @param address the address of the entity whose metadata changed
     */
    private void updateInputNames(NavAddress address) {

        NavAddressMethod method = address.getMethod();
       
        if (method != NavAddress.FUNCTION_METHOD &&
            method != NavAddress.CLASS_METHOD_METHOD &&
            method != NavAddress.DATA_CONSTRUCTOR_METHOD) {
           
            return;
        }
       
        // If this was a functional agent, then we need to update its gems on the table top.
        GemEntity entity = getPerspective().getWorkspace().getGemEntity(address.toFeatureName().toQualifiedName());
        FunctionalAgentMetadata metadata = (FunctionalAgentMetadata) NavAddressHelper.getMetadata(this, address.withAllStripped());
        ArgumentMetadata[] argMetadata = metadata.getArguments();
       
        for (final Gem gem : gemCutter.getTableTop().getGemGraph().getGems()) {
           
            if (gem instanceof FunctionalAgentGem) {
               
                GemEntity gemEntity = ((FunctionalAgentGem) gem).getGemEntity();
               
                if (gemEntity.equals(entity)) {

                    // We need to update the inputs of this gem
                    PartInput[] inputs = gem.getInputParts();
                   
                    for (int i = 0; i < inputs.length; i++) {
                       
                        // Update the original name for this input.
                        String displayName = i < argMetadata.length ? argMetadata[i].getDisplayName() : null;
                        String nameFromCode = i < entity.getNNamedArguments() ? entity.getNamedArgument(i) : null;
                       
                        inputs[i].setOriginalInputName(displayName != null ? displayName : nameFromCode);
                    }
                }
            }
        }
    }
   
    /**
     * Name checks the table top to disambiguate any input names that may have become ambiguous
     * as a result of the metadata changing. Also updates the TableTopExplorer to correctly
     * display the new input names.
     */
    private void nameCheckTableTop() {

        // Update the tabletop for the new gem graph state.  Among other things, this will ensure arg name disambiguation.
        gemCutter.getTableTop().updateForGemGraph();
       
        // Since we don't know which input names actually changed as a result of
        // name checking the table top, we simply have to update all nodes in the explorer.
       
        TableTopExplorer tableTopExplorer = gemCutter.getTableTopExplorer();
        Set<DisplayedGem> displayedGemSet = gemCutter.getTableTop().getDisplayedGems();
       
        for (final DisplayedGem gem : displayedGemSet) {
           
            PartInput[] inputs = gem.getGem().getInputParts();
           
            for (final PartInput input : inputs) {
                TreeNode node = tableTopExplorer.getInputNode(input);
               
                if (node != null) {
                    tableTopExplorer.getExplorerTreeModel().nodeChanged(node);
                }
            }
        }
    }
   
    /**
     * @see org.openquark.gems.client.navigator.NavFrameOwner#searchMetadata(java.lang.String)
     */
    public List<NavAddress> searchMetadata(String searchString) {
        return navFrame.searchMetadata(searchString);
    }
   
    /**
     * Tests all metadata examples.
     */
    public void testMetadataExamples() {       
        String conciseTitle = "Concise Output?";
        String conciseMessage = "Would you like to suppress the output of successful metadata tests?";
        int conciseResponse = JOptionPane.showOptionDialog(gemCutter,
                conciseMessage,
                conciseTitle,
                JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.QUESTION_MESSAGE,
                null, null, null);
       
        // If the user closed the dialog or hit cancel, do nothing
        if (conciseResponse == JOptionPane.CANCEL_OPTION || conciseResponse == JOptionPane.CLOSED_OPTION) {
            return;
        }

        String autoTitle = "Skip non-automatic examples?";
        String autoMessage = "Would you like to run only those examples set to run automatically?";
        int autoResponse = JOptionPane.showOptionDialog(gemCutter,
                autoMessage,
                autoTitle,
                JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.QUESTION_MESSAGE,
                null, null, null);
       
        // If the user closed the dialog or hit cancel, do nothing
        if (autoResponse == JOptionPane.CANCEL_OPTION || autoResponse == JOptionPane.CLOSED_OPTION) {
            return;
        }
       
        navFrame.testMetadataExamples(conciseResponse == JOptionPane.YES_OPTION, autoResponse==JOptionPane.YES_OPTION);
    }

    /**
     * {@inheritDoc}
     */
    public Locale getLocaleForMetadata() {
        return GemCutter.getLocaleFromPreferences();
    }
}
TOP

Related Classes of org.openquark.gems.client.NavigatorAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.