Package gov.nasa.arc.mct.gui

Source Code of gov.nasa.arc.mct.gui.View

/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is 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://www.apache.org/licenses/LICENSE-2.0.
*
* 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.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
/**
* MCTGUIComponent.java Sep 2, 2008
*
* This code is the property of the National Aeronautics and Space
* Administration and was produced for the Mission Control Technologies (MCT)
* project.
*
*/
package gov.nasa.arc.mct.gui;

import gov.nasa.arc.mct.components.AbstractComponent;
import gov.nasa.arc.mct.components.ExtendedProperties;
import gov.nasa.arc.mct.lock.manager.LockObserver;
import gov.nasa.arc.mct.platform.spi.PlatformAccess;
import gov.nasa.arc.mct.policy.ExecutionResult;
import gov.nasa.arc.mct.policy.PolicyContext;
import gov.nasa.arc.mct.policy.PolicyInfo;
import gov.nasa.arc.mct.roles.events.AddChildEvent;
import gov.nasa.arc.mct.roles.events.FocusEvent;
import gov.nasa.arc.mct.roles.events.PropertyChangeEvent;
import gov.nasa.arc.mct.roles.events.ReloadEvent;
import gov.nasa.arc.mct.roles.events.RemoveChildEvent;
import gov.nasa.arc.mct.services.component.ViewInfo;
import gov.nasa.arc.mct.services.internal.component.ComponentInitializer;
import gov.nasa.arc.mct.util.logging.MCTLogger;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.OverlayLayout;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;

/**
* Implements a skeleton of a view. Component developers
* should derive from this class to implement their own view manifestation
* classes.
*/
@SuppressWarnings("serial")
public abstract class View extends JPanel implements ViewProvider, LockObserver {

    /**
     * Property name used to register property listeners to respond to
     * a view stale event triggered by stale object.
     */
    public static final String VIEW_STALE_PROPERTY = "VIEW_STALE_PROPERTY";

    /**
     * This member represents the data flavor used in the platform for drag and drop. 
     */
    public static final DataFlavor DATA_FLAVOR;
   
    static {
        RepaintManager.setCurrentManager(GlassPanelRepaintManager.getInstance());
        DataFlavor localDataFlavor=null;
        try {
            localDataFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType) {
               @Override
               public Class<?> getRepresentationClass() {
                   return View.class;
              
            };
        } catch (ClassNotFoundException e) {
            MCTLogger.getLogger(View.class).error("error when creating data flavor",e);
        }
        DATA_FLAVOR = localDataFlavor;
    }

   
    /**
     * A dummy view manifestation, used as a sentinel value.
     */
    public final static View NULL_VIEW_MANIFESTATION = new View() {
        @Override
        public AbstractComponent getManifestedComponent() {
            return AbstractComponent.NULL_COMPONENT;
        }

        @Override
        public void enterLockedState() {
            // TODO Auto-generated method stub
           
        }

        @Override
        public void exitLockedState() {
            // TODO Auto-generated method stub
           
        }

        @Override
        public void processDirtyState() {
            // TODO Auto-generated method stub
           
        }
    };
   
    private static final SelectionProvider NULL_SELECTION_PROVIDER = new SelectionProvider() {

        @Override
        public void addSelectionChangeListener(PropertyChangeListener listener) {
        }

        @Override
        public Collection<View> getSelectedManifestations() {
            return Collections.emptyList();
        }

        @Override
        public void removeSelectionChangeListener(PropertyChangeListener listener) {
        }
       
        @Override
        public void clearCurrentSelections() {
        }
       
    };
   
    private AbstractComponent manifestedComponent;
   
    /** The listener for this view manifestation. */
    protected ViewListener viewManifestationListener;
   
    private JComponent controlManifestation;
    private ControlWrapper controlWrapper;
    private NamingContext namingContext;
    private ViewInfo info;
       
    /**
     * Creates a new view manifestation with no parent view role.
     * This constructor should be followed by a call to {@link #setInfo(ViewInfo)}.
     * This constructor should be used internally only.
     */
    public View() {
        super(new GridLayout(1, 1));
    }
   
    /**
     * Creates a new instance with the specified component and view info.
     * @param component to bind this view to.
     * @param viewInfo used to create this component.
     */
    public View(AbstractComponent component, ViewInfo viewInfo) {
        this();
        setManifestedComponent(component);
        setInfo(viewInfo);
    }
       
    /**
     * Updates the view manifestation because of a change in the model
     * or relationships with the parent component.
     */
    public void updateMonitoredGUI() {
    }
   
    /**
     * Updates the view manifestation because a new child component has
     * been added.
     *
     * @param event the add child event
     */
    public void updateMonitoredGUI(AddChildEvent event) {
        //
    }
   
    /**
     * Updates the view manifestation because the component state has been
     * reloaded from persistent storage.
     *
     * @param event the reload event
     */
    public void updateMonitoredGUI(ReloadEvent event) {
        //
    }
   
    /**
     * Updates the view manifestation because a child component has
     * been removed.
     *
     * @param event the remove child event
     */
    public void updateMonitoredGUI(RemoveChildEvent event) {
        //
    }
   
    /**
     * Updates the view manifestation because of a change in focus.
     *
     * @param event the focus change event
     */
    public void updateMonitoredGUI(FocusEvent event) {
        //
    }
   
    /**
     * Updates the view manifestation because of a change in a
     * component property.
     *
     * @param event the property change event
     */
    public void updateMonitoredGUI(PropertyChangeEvent event) {
        //
    }
   
    // This method is to get around the problem that TreeNode is not subclass of JComponent.
    /**
     * Adds a related GUI component that will be updated when this
     * one is.
     *
     * @param gui the new monitored GUI component
     * @param <T> the type of the monitored GUI component
     */
    public<T> void addMonitoredGUI(T gui) {
        //
    }
   
    /**
     * Invoked when the view properties or the underlying component was persisted to the persistence store. The default
     * implementation does nothing.
     */
    public void viewPersisted() {
       
    }
   
    /**
     * Return the selection provider for this manifestation. The default implementation returns
     * a null provider (does not broadcast events). Views targeting the housing, content or directory area must return a selection provider.
     * @return selection provider for this manifestation
     */
    public SelectionProvider getSelectionProvider() {
        return NULL_SELECTION_PROVIDER;
    }
   
    /**
     * Sets the view manifestation listener for this view manifestation.
     *
     * @param guiListener the new listener
     */
    public void setViewListener(ViewListener guiListener) {
        this.viewManifestationListener = guiListener;
    }
   
    /**
     * Gets the view manifestation listener.
     *
     * @return the current view manifestation listener
     */
    public ViewListener getViewListener() {
        return this.viewManifestationListener;
    }

    /**
     * Gets the component that this view manifestation is associated
     * with.
     *
     * @return the associated MCT component
     */
    public AbstractComponent getManifestedComponent() {
        return manifestedComponent;
    }
   
    /**
     * Sets the component that this view manifestation is associated
     * with.
     *
     * @param manifestedComponent the MCT component
     */
    public void setManifestedComponent(AbstractComponent manifestedComponent) {
        this.manifestedComponent = manifestedComponent;
    }
   
    @Override
    public View getHousedViewManifestation() {
        return this;
    }

    @Override
    public boolean setHousedViewManifestation(ViewInfo vi) {
        return false;
    }
   
    @Override
    public boolean equals(Object obj) {
        if (! (obj instanceof View)) { return false; }
        if (this == NULL_VIEW_MANIFESTATION || obj == NULL_VIEW_MANIFESTATION) { return false; }
       
        return this == obj;
    }
   
    @Override
    public void processMouseEvent(MouseEvent e) {
        super.processMouseEvent(e);
    }
   
    @Override
    public void enterLockedState() {
        if (controlWrapper != null)
            controlWrapper.controlGlass.changeState(false);
    }

    @Override
    public void exitLockedState() {
        if (controlWrapper != null)
            controlWrapper.controlGlass.changeState(true);
    }

    @Override
    public void processDirtyState() {
    }

    /**
     * A view manifestation may be associated with a control manifestation,
     * which contains GUI controls that can manipulate the view manifestation.
     * The control manifestation will appear in the control area, which is placed
     * above the view manifestation. The control area is not initially visible
     * until the user clicks on the twistie (triangle) located in the title bar or a tab.
     *
     * @return the control manifestation which is a <code>JComponent</code>;
     * if no control manifestation is necessary for the view, then the method
     * returns null. If there is a control manifestation available, then
     * the method calls executes the
     * <code>PolicyInfo.CategoryType.SHOW_HIDE_CTRL_MANIFESTATION</code> policy
     * category to check if the control manifestation should be available, i.e,
     * if the twistie should be visible.
     */
    public final JComponent getControlManifestation() {
        PolicyContext policyContext = new PolicyContext();
        policyContext.setProperty(PolicyContext.PropertyName.TARGET_COMPONENT.getName(), getManifestedComponent());       
        policyContext.setProperty(PolicyContext.PropertyName.TARGET_VIEW_INFO.getName(), getInfo());
        ExecutionResult result = PlatformAccess.getPlatform().getPolicyManager().execute(PolicyInfo.CategoryType.SHOW_HIDE_CTRL_MANIFESTATION.getKey(), policyContext);
        if (!result.getStatus())
            return null;
       
        controlManifestation = initializeControlManifestation();
        if (controlManifestation != null) {
            controlWrapper = new ControlWrapper(controlManifestation);
            if (isLocked())
                exitLockedState();
            return controlWrapper;
        }
        return null;
    }
    /**
     * Provides a list of widgets to be displayed in the status
     * area of a window, canvas panel, and an inspector area.
     * @return the list of status widgets provided bu this manifestation
     */
    public List<? extends JComponent> getStatusWidgets() {
        return Collections.emptyList();
    }

    /**
     * Determines if this view owns the content. For example, the content of a canvas view contains panels,
     * and the canvas view <em>owns</em> the settings for each panel. This makes the canvas view a
     * content owner. In the MCT UI, a content owner <em>must</em> provide its own inspector view, which gets
     * populated in the right pane of a window, when its content is being inspected. 
     * @return true if the view is a content owner; false otherwise. Returns false by default.
     */
    public boolean isContentOwner() {
        return false;
    }
   
    /**
     * This method must be overridden to create the control manifestation (if any)
     * of this view manifestation.
     * @return the control manifestation
     */
    protected JComponent initializeControlManifestation() {
        return null;
    }
   
    /**
     * Checks if this manifestation is currently locked. A manifestation is not modifiable when locked.
     * @return true if this manifestation is currently locked; false otherwise.
     */
    public final boolean isLocked() {
       return false;
    }
   
    /**
     * Calls the <code>MenuManager</code> that returns the <code>JPopupMenu</code> for this manifestation.
     * The manifestations returned from {@link ActionContext#getSelectedManifestations()} will be the
     * selected manifestations from the containing housing.
     *
     * @return the popup menu for the selected manifestations
     */
    public final JPopupMenu getManifestationPopupMenu() {
        return PlatformAccess.getPlatform().getMenuManager().getManifestationPopupMenu(this);
    }
   
    /**
     * If this manifestation uses an overlay layout (i.e., <code>OverlayLayout</code>),
     * it may be desirable for the overlay pane to paint over the pane under it as it
     * repaints itself. This method adds these <code>JComponent</code>s to the internal
     * <code>RepaintManager</code> to ensure this behavior.
     * @param mainPane the pane under the overlay pane
     * @param overlayPane the overlay pane
     */
    public final void setRepaintComponentPair(JComponent mainPane, JComponent overlayPane) {
        GlassPanelRepaintManager.registerRepaintPair(mainPane, overlayPane);
    }
   
    /**
     * Gets the naming context for this view.
     * @return the namingContext
     */
    public final NamingContext getNamingContext() {
        return namingContext;
    }

    /**
     * Sets the naming context for this view.
     * @param namingContext the namingContext to set
     */
    public final void setNamingContext(NamingContext namingContext) {
        this.namingContext = namingContext;
        handleNamingContextChange();
    }

    /**
     * This method is invoked when the naming context is changed. The implementing view should adjust the labels in response to an
     * invocation of this method. The default implementation of this method does nothing.
     */
    protected void handleNamingContextChange() {
       
    }
   
    /**
     * Get the view which is a container for this specific view.
     * May return null if this is not known by the view.
     * @return the parent of this view
     */
    public View getParentView() {
        return null;
    }
   
    /**
     * Gets the info used to create this view.
     * @return the type info used to create this view.
     */
    public ViewInfo getInfo() {
        return info;
    }

    /**
     * Sets the info used to create this view.
     * @param type the type to set
     */
    private void setInfo(ViewInfo type) {
        this.info = type;
    }

    /**
     * Implements the glass panel. The glass panel is a <code>JComponent</code>
     * that paints a translucent white finish and a lock pad when the underlying
     * view manifestation is locked. 
     */
    static final class GlassPanel extends JComponent {
        private static final String TOOLTIP_TEXT = "<html>This manifestation is currently locked.<br>Please unlock the inspector title to make changes.</html>";
        private MouseListener mouseBlocker = new MouseAdapter() {};
        private MouseMotionListener motionBocker = new MouseAdapter() {};
        private KeyListener keyBlocker = new KeyAdapter() {};
        private boolean isEnabled;
       
        /**
         * Creates a glass panel.
         */
        public GlassPanel() {
            addComponentListener(new ComponentAdapter() {
                @Override
                public void componentShown(ComponentEvent e) {
                    requestFocusInWindow();
                }
            });
        }
       
        @Override
        protected void paintComponent(Graphics g) {
            if (isEnabled) {
                g.setColor(new Color(1.0f, 1.0f, 1.0f, isEnabled ? .45f : 0));
                Rectangle clip = g.getClipBounds();
                g.fillRect(clip.x, clip.y, clip.width, clip.height);
            }
        }
       
        /**
         * Sets the state of the glass panel.
         * @param isEnabled true when is enabled; false otherwise
         */
        public void changeState(boolean isEnabled) {
            if (this.isEnabled == isEnabled)
                return;
           
            this.isEnabled = isEnabled;
            if (isEnabled) {
                addMouseListener(mouseBlocker);
                addMouseMotionListener(motionBocker);
                addKeyListener(keyBlocker);
                setFocusTraversalKeysEnabled(false);
                setToolTipText(TOOLTIP_TEXT);
            } else {
                removeMouseListener(mouseBlocker);
                removeMouseMotionListener(motionBocker);
                removeKeyListener(keyBlocker);
                setFocusTraversalKeysEnabled(true);
                setToolTipText(null);
            }
            requestFocus();
            repaint();
        }
    }
   
    /**
     * Implements a wrapper for the GUI control associated to the
     * view manifestation. 
     */
    static final class ControlWrapper extends JPanel {
        private GlassPanel controlGlass;
       
        public ControlWrapper(JComponent controlManifestation) {
            OverlayLayout controlOverlayLayout = new OverlayLayout(this);
            controlGlass = new GlassPanel();
            setLayout(controlOverlayLayout);
            add(controlGlass);
            add(controlManifestation);
        }
       
        GlassPanel getGlassPanel() {
            return controlGlass;
        }
    }
   
    static class GlassPanelRepaintManager extends RepaintManager {
       
        private static Map<WeakReference<JComponent>, WeakReference<JComponent>> repaintPairs = new HashMap<WeakReference<JComponent>, WeakReference<JComponent>>();
        private static final GlassPanelRepaintManager manager = new GlassPanelRepaintManager();
       
        GlassPanelRepaintManager() {}
       
        public static GlassPanelRepaintManager getInstance() {
            return manager;
        }
       
        public static void registerRepaintPair(JComponent mainPane, JComponent overlayPane) {
            Iterator<WeakReference<JComponent>> iterator = repaintPairs.keySet().iterator();
            while (iterator.hasNext()) {
                WeakReference<JComponent> ref = iterator.next();
                JComponent pane = ref.get();
                if (pane != null) {
                    if (SwingUtilities.isDescendingFrom(mainPane, pane))
                        return;
                    if (SwingUtilities.isDescendingFrom(pane, mainPane))
                        iterator.remove();
                }
            }
            repaintPairs.put(new WeakReference<JComponent>(mainPane), new WeakReference<JComponent>(overlayPane));
        }
       
        @Override
        public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
            ControlWrapper controlWrapper = (ControlWrapper) SwingUtilities.getAncestorOfClass(ControlWrapper.class, c);
            if (controlWrapper != null) {
                Rectangle bounds = controlWrapper.controlGlass.getBounds();
                addDirtyRegionToSuperRepaintManager(controlWrapper.controlGlass, bounds.x, bounds.y, (int) bounds.getWidth(), (int) bounds.getHeight());
                return;
            }

            int overlayRegionsCount = 0;
            Iterator<WeakReference<JComponent>> iterator = repaintPairs.keySet().iterator();           
            while (iterator.hasNext()) {
                WeakReference<JComponent> mainPaneRef = iterator.next();
                JComponent mainPane = mainPaneRef.get();
                if (mainPane == null) {
                    iterator.remove();
                    continue;
                }
                               
                if (SwingUtilities.isDescendingFrom(c, mainPane)) {
                    JComponent overlayPane = repaintPairs.get(mainPaneRef).get();
                    Rectangle bounds = overlayPane.getBounds();
                    addDirtyRegionToSuperRepaintManager(overlayPane, bounds.x, bounds.y, (int) bounds.getWidth(), (int) bounds.getHeight());
                    overlayRegionsCount++;
                }
            }           
            if (overlayRegionsCount > 0)
                return;
           
            addDirtyRegionToSuperRepaintManager(c, x, y, w, h);
        }
       
        void addDirtyRegionToSuperRepaintManager(JComponent c, int x, int y, int w, int h) {
            super.addDirtyRegion(c, x, y, w, h);
        }
       
    }
   
    /**
     * Returns the view properties of this view type.
     * @return non-null <code>ExtendedProperties</code>
     */
    public ExtendedProperties getViewProperties() {
        String viewType = getInfo().getType();
        ComponentInitializer capability = getManifestedComponent().getCapability(ComponentInitializer.class);
        ExtendedProperties props = capability.getViewRoleProperties(viewType);
        if (props == null) {
            props = new ExtendedProperties();
            capability.setViewRoleProperty(viewType, props);           
        }
        return props;
    }
   
    /**
     * Fires property change event to registered listeners upon view stale.
     * @param isStale true if view is stale; false otherwise.
     */
    public final void notifyStaleState(boolean isStale) {
        firePropertyChange(VIEW_STALE_PROPERTY, null, isStale);
    }
}
TOP

Related Classes of gov.nasa.arc.mct.gui.View

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.