Package org.apache.airavata.xbaya.ui.widgets.component

Source Code of org.apache.airavata.xbaya.ui.widgets.component.ComponentSelector

/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.
*
*/

package org.apache.airavata.xbaya.ui.widgets.component;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceAdapter;
import java.awt.dnd.DragSourceListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.apache.airavata.common.utils.SwingUtil;
import org.apache.airavata.workflow.model.component.Component;
import org.apache.airavata.workflow.model.component.ComponentException;
import org.apache.airavata.workflow.model.component.ComponentOperationReference;
import org.apache.airavata.workflow.model.component.ComponentReference;
import org.apache.airavata.workflow.model.component.ComponentRegistry;
import org.apache.airavata.workflow.model.component.ComponentRegistryException;
import org.apache.airavata.workflow.model.component.ws.WSComponent;
import org.apache.airavata.workflow.model.exceptions.WorkflowRuntimeException;
import org.apache.airavata.xbaya.XBayaEngine;
import org.apache.airavata.xbaya.component.registry.ComponentController;
import org.apache.airavata.xbaya.ui.utils.ErrorMessages;
import org.apache.airavata.xbaya.ui.widgets.XBayaComponent;
import org.apache.airavata.xbaya.ui.widgets.component.ComponentSelectorEvent.ComponentSelectorEventType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The ComponentTreeViewer class shows the selectedComponent tree.
*
*/
public class ComponentSelector implements XBayaComponent {

    /**
     * The title.
     */
    public static final String TITLE = "Component List";

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

    private XBayaEngine engine;

    private JTree tree;

    private ComponentTreeModel treeModel;

    private ComponentReference selectedComponentReference;

    private Component selectedComponent;

    private List<ComponentSelectorListener> listeners;

    private DragSourceListener dragSourceListener;

    private JPopupMenu popup;

    /**
     * @param engine
     */
    public ComponentSelector(XBayaEngine engine) {
        this.engine = engine;
        this.listeners = new LinkedList<ComponentSelectorListener>();
        initGUI();
    }

    /**
     * @return the Pane
     */
    public JTree getSwingComponent() {
        return this.tree;
    }

    /**
     * Adds a new selectedComponent registry to the end of the tree.
     *
     * @param componentTree
     */
    public void addComponentTree(ComponentTreeNode componentTree) {
        addComponentTree(-1, componentTree);
    }

    public void removeComponentTree(final ComponentTreeNode componentTree) {
        ComponentSelector.this.treeModel.removeNodeFromParent(componentTree);
//      SwingUtilities.invokeLater(new Runnable() {
//            public void run() {
//                ComponentSelector.this.treeModel.removeNodeFromParent(componentTree);
//            }
//
//        });
    }

    public synchronized void removeComponentRegistry(final String componentRegistryName) {
        ComponentTreeNode root = ComponentSelector.this.treeModel.getRoot();
        ComponentTreeNode[] treeNodes = root.getChildren().toArray(new ComponentTreeNode[]{});
        for(ComponentTreeNode treeNode:treeNodes){
            if (treeNode.getComponentRegistry().getName().equals(componentRegistryName)){
                root.remove(treeNode);
            }
        }
        treeModel.reload();
    }
   
    /**
     * Adds a new selectedComponent registry to the specified location.
     *
     * @param index
     *            The index to ineart a new selectedComponent registry
     * @param componentTree
     */
    public void addComponentTree(final int index, final ComponentTreeNode componentTree) {

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                ComponentTreeNode root = ComponentSelector.this.treeModel.getRoot();
                if (index < 0) {
                    // Have to go through DefaultTreeModol to dynamically
                    // add a node
                    ComponentSelector.this.treeModel.addNodeInto(componentTree, root);
                } else {
                    // Have to go through DefaultTreeModol to dynamically
                    // add a node
                    ComponentSelector.this.treeModel.insertNodeInto(componentTree, root, index);
                }
                makeVisible(componentTree);
            }

        });
    }

    /**
     * Removes a registry currently selected.
     */
    public void removeSelectedRegistry() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                TreePath selectionPath = ComponentSelector.this.tree.getSelectionPath();
                ComponentTreeNode selectedNode = (ComponentTreeNode) selectionPath.getLastPathComponent();
                if (selectedNode.getLevel() == 1) {
                    ComponentSelector.this.treeModel.removeNodeFromParent(selectedNode);
                }
            }
        });
    }

    /**
     * @throws ComponentRegistryException
     */
    public void updateSelectedRegistry() throws ComponentRegistryException {
        final TreePath[] selectionPathHolder = new TreePath[1];
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    selectionPathHolder[0] = ComponentSelector.this.tree.getSelectionPath();
                }
            });
        } catch (InterruptedException e) {
            // Should not happen.
            throw new WorkflowRuntimeException(e);
        } catch (InvocationTargetException e) {
            // Should not happen.
            throw new WorkflowRuntimeException(e);
        }

        TreePath selectionPath = selectionPathHolder[0];
        if (selectionPath == null) {
            // TODO this case should be handled in the menu before comming here.
            return;
        }

        if (selectionPath.getPathCount() >= 2) {
            final ComponentTreeNode selectedNode = (ComponentTreeNode) selectionPath.getPath()[1];
            ComponentRegistry registry = selectedNode.getComponentRegistry();
            final ComponentTreeNode componentTree = ComponentController.getComponentTree(registry);

            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    ComponentTreeNode root = ComponentSelector.this.treeModel.getRoot();
                    int index = root.getIndex(selectedNode);
                    ComponentSelector.this.treeModel.removeNodeFromParent(selectedNode);
                    ComponentSelector.this.treeModel.insertNodeInto(componentTree, root, index);
                }
            });
        }
    }

    /**
     * Updates all the registry entries.
     *
     * @throws ComponentRegistryException
     */
    public void update() throws ComponentRegistryException {
        final List<ComponentRegistry> registries = new ArrayList<ComponentRegistry>();
        if (SwingUtilities.isEventDispatchThread()) {
            getRegistries(registries);
        } else {
            try {
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        getRegistries(registries);
                    }
                });
            } catch (InterruptedException e) {
                // Should not happen.
                throw new WorkflowRuntimeException(e);
            } catch (InvocationTargetException e) {
                // Should not happen.
                throw new WorkflowRuntimeException(e);
            }
        }

        final List<ComponentTreeNode> newSubTrees = new ArrayList<ComponentTreeNode>();
        for (ComponentRegistry registry : registries) {
            ComponentTreeNode componentTree = ComponentController.getComponentTree(registry);
            newSubTrees.add(componentTree);
        }

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                ComponentTreeNode root = ComponentSelector.this.treeModel.getRoot();
                ComponentSelector.this.treeModel.removeChildren(root);
                logger.debug("Removed all");
                for (ComponentTreeNode subTree : newSubTrees) {
                    ComponentSelector.this.treeModel.addNodeInto(subTree, root);
                }
                makeVisible((ComponentTreeNode) root.getFirstChild());
            }
        });

    }

    /**
     * Returns the selectedComponent.
     *
     * @return The selectedComponent
     */
    public Component getSelectedComponent() {
        return this.selectedComponent;
    }

    /**
     * @param listener
     */
    public synchronized void addComponentSelectorListener(ComponentSelectorListener listener) {
        this.listeners.add(listener);
    }

    /**
     * @param listener
     */
    public synchronized void removeComponentSelectorListener(ComponentSelectorListener listener) {
        this.listeners.remove(listener);
    }

    private void dragGestureRecognized(DragGestureEvent event) {
        if (this.selectedComponentReference != null) {
            event.startDrag(DragSource.DefaultCopyDrop,
                    new ComponentSourceTransferable(this.selectedComponentReference), this.dragSourceListener);
        }
    }

    private List<ComponentRegistry> getRegistries(List<ComponentRegistry> registries) {
        ComponentTreeNode root = this.treeModel.getRoot();
        for (ComponentTreeNode componentTree : root.getChildren()) {
            registries.add(componentTree.getComponentRegistry());
        }
        return registries;
    }

    private void makeVisible(ComponentTreeNode node) {
        // Make sure the user can see the new node, but don't scroll to
        // right.
        TreePath treePath = new TreePath(node.getPath());
        Rectangle bounds = ComponentSelector.this.tree.getPathBounds(treePath);
        if (bounds != null) {
            // Prevent right scroll.
            bounds.x = 0;
            bounds.width = 0;
            this.tree.scrollRectToVisible(bounds);
        } else {
            // null during the initialization.
            this.tree.scrollPathToVisible(treePath);
        }
    }

    /**
     * This method is called when a component is selected. It reads the component information from the server and set
     * the selectedComponent.
     *
     * @param treePath
     *            The path of the selected selectedComponent.
     */
    private void select(TreePath treePath) {
        final ComponentTreeNode selectedNode = (ComponentTreeNode) treePath.getLastPathComponent();
        final ComponentReference componentReference = selectedNode.getComponentReference();
        selectComponent(null);
        this.selectedComponentReference = null;
        if (componentReference != null) {
            this.selectedComponentReference = componentReference;
            new Thread() {
                @Override
                public void run() {
                    try {
                        // get all components and check the number of
                        // components. If there are multiple, expand the tree.
                        final List<? extends Component> components = componentReference.getComponents();
                        if (components.size() == 1) {
                            selectComponent(components.get(0));
                        } else {
                            SwingUtilities.invokeLater(new Runnable() {
                                public void run() {
                                    expandTreeLeaf(selectedNode, components);
                                }
                            });
                        }

                    } catch (ComponentException e) {
                        selectComponent(null);
                        ComponentSelector.this.engine.getGUI().getErrorWindow().error(ErrorMessages.COMPONENT_FORMAT_ERROR, e);
                    } catch (ComponentRegistryException e) {
                        selectComponent(null);
                        ComponentSelector.this.engine.getGUI().getErrorWindow().error(ErrorMessages.COMPONENT_LOAD_ERROR, e);
                    } catch (RuntimeException e) {
                        selectComponent(null);
                        ComponentSelector.this.engine.getGUI().getErrorWindow().error(ErrorMessages.COMPONENT_LOAD_ERROR, e);
                    } catch (Exception e) {
                        selectComponent(null);
                        ComponentSelector.this.engine.getGUI().getErrorWindow().error(ErrorMessages.COMPONENT_LOAD_ERROR, e);
                    }
                }
            }.start();

        }
    }

    private void expandTreeLeaf(ComponentTreeNode selectedNode, List<? extends Component> components) {
        ComponentReference componentReference = selectedNode.getComponentReference();
        ComponentTreeNode newNode = new ComponentTreeNode(componentReference.getName());

        ComponentTreeNode parent = (ComponentTreeNode) selectedNode.getParent();
        int index = this.treeModel.getIndexOfChild(parent, selectedNode);
        this.treeModel.removeNodeFromParent(selectedNode);
        this.treeModel.insertNodeInto(newNode, parent, index);

        for (Component component : components) {
            WSComponent wsComponent = (WSComponent) component;
            String operationName = wsComponent.getOperationName();
            ComponentOperationReference reference = new ComponentOperationReference(operationName, wsComponent);
            ComponentTreeNode child = new ComponentTreeNode(reference);
            this.treeModel.addNodeInto(child, newNode);
        }
        // expand
        TreeNode[] path = newNode.getPath();
        this.tree.expandPath(new TreePath(path));
    }

    private void selectComponent(Component component) {
        this.selectedComponent = component;
        notifyListeners(new ComponentSelectorEvent(ComponentSelectorEventType.COMPONENT_SELECTED, this, component));
    }

    private void showPopupIfNecessary(MouseEvent event) {
        Point point = event.getPoint();
        TreePath path = this.tree.getClosestPathForLocation(point.x, point.y);
        this.tree.setSelectionPath(path);

        if (path.getPathCount() >= 2) {
            this.popup.show(event.getComponent(), point.x, point.y);
        }
    }

    private void notifyListeners(ComponentSelectorEvent event) {
        for (ComponentSelectorListener listener : this.listeners) {
            listener.componentSelectorChanged(event);
        }
    }

    private void initGUI() {
        this.treeModel = new ComponentTreeModel(new ComponentTreeNode("Components"));
        this.tree = new JTree(this.treeModel);

        // Add a tool tip.
        ToolTipManager.sharedInstance().registerComponent(this.tree);
        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer() {
            @Override
            public java.awt.Component getTreeCellRendererComponent(JTree t, Object value, boolean sel,
                    boolean expanded, boolean leaf, int row, boolean focus) {
                super.getTreeCellRendererComponent(t, value, sel, expanded, leaf, row, focus);

                ComponentTreeNode node = (ComponentTreeNode) value;
                if (node.getComponentReference() == null) {
                    setToolTipText(null);
                } else {
                    setToolTipText("Drag a component to the composer to add");
                }
                return this;
            }
        };

        // Change icons
        try {
            renderer.setOpenIcon(SwingUtil.createImageIcon("opened.gif"));
            renderer.setClosedIcon(SwingUtil.createImageIcon("closed.gif"));
            renderer.setLeafIcon(SwingUtil.createImageIcon("leaf.gif"));
        } catch (RuntimeException e) {
            logger.warn("Failed to load image icons.  " + "It will use the default icons instead.", e);
        }

        this.tree.setCellRenderer(renderer);
        this.tree.setShowsRootHandles(true);
        this.tree.setEditable(false);
        this.tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        this.tree.addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(TreeSelectionEvent event) {
                // Doesn't do anything if deselected, which happens during the
                // update.
                if (event.isAddedPath()) {
                    TreePath path = event.getPath();
                    select(path);
                }
            }
        });

        // Drag and dtop
        DragGestureListener dragGestureListener = new DragGestureListener() {
            public void dragGestureRecognized(DragGestureEvent event) {
                ComponentSelector.this.dragGestureRecognized(event);
            }
        };
        DragSource dragSource = DragSource.getDefaultDragSource();
        dragSource.createDefaultDragGestureRecognizer(this.tree, DnDConstants.ACTION_COPY_OR_MOVE, dragGestureListener);

        this.dragSourceListener = new DragSourceAdapter() {
            // Overwrite some methods when needed.
        };

        // Popup
        this.tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent event) {
                if (event.isPopupTrigger()) {
                    showPopupIfNecessary(event);
                }
            }
        });
        createNodePopupMenu();
    }

    private void createNodePopupMenu() {
        this.popup = new JPopupMenu();
        JMenuItem refreshItem = new JMenuItem("Refresh Registry");
        refreshItem.addActionListener(new AbstractAction() {
            public void actionPerformed(ActionEvent event) {
                new Thread() {
                    @Override
                    public void run() {
                        try {
                            updateSelectedRegistry();
                        } catch (ComponentRegistryException e) {
                            ComponentSelector.this.engine.getGUI().getErrorWindow().error(
                                    ErrorMessages.COMPONENT_LIST_LOAD_ERROR, e);
                        } catch (RuntimeException e) {
                            ComponentSelector.this.engine.getGUI().getErrorWindow().error(
                                    ErrorMessages.COMPONENT_LIST_LOAD_ERROR, e);
                        } catch (Error e) {
                            ComponentSelector.this.engine.getGUI().getErrorWindow().error(ErrorMessages.UNEXPECTED_ERROR, e);
                        }
                    }
                }.start();
            }
        });
        this.popup.add(refreshItem);
    }

    public void refresh() {
        this.getSwingComponent().repaint();

        this.tree.repaint();
    }

}
TOP

Related Classes of org.apache.airavata.xbaya.ui.widgets.component.ComponentSelector

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.