Package simtools.ui

Source Code of simtools.ui.SourceTree

/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This program 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 2.1 of the License, or (at your option) any later version.
*
* This program 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 this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2003, by :
*     Corporate:
*         Astrium SAS
*         EADS CRC
*     Individual:
*         Nicolas Brodu
*
* $Id: SourceTree.java,v 1.13 2008/10/03 12:23:43 ogor Exp $
*
* Changes
* -------
* 25-Sep-2003 : Initial public release (NB);
*
*/

package simtools.ui;

import java.awt.Cursor;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;
import java.util.regex.Pattern;

import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.TransferHandler;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourceCollection;
import simtools.data.DataSourcePool;
import simtools.data.DataSourcePoolEvent;
import simtools.data.DataSourcePoolListener;

/**
* A tree specialized in displaying and filtering data sources.
*
* Uses and listens to the data source pool of JSynoptic.
*
* @author Nicolas Brodu
*
* @version 1.0 2001
*/
public class SourceTree extends JTree implements DataSourcePoolListener, ActionListener {

  protected DataSourcePool pool;
  protected DefaultNode rootNode;
  protected DefaultTreeModel treeModel;
  protected JMenuItem sourceInfo;
  protected JMenuItem sourceDelete;
  protected double actionX, actionY;
 
  protected FilterPattern filterPattern;
  protected String currentFilterValue = "";

  protected static HashMap sourceTreePool=new HashMap();
  protected static Class sourceTreeClass=SourceTree.class;


  /**
   * A pool of source tree panels  to reduce memory foot print
   * Keep in mind that each JComponent can be displayed only one time
   * @param id an identifier to define the reuse or not from the pool
   * @return the source tree
     */
  public static SourceTree getFromPool(String id){
      if(sourceTreePool.get(id)==null){
          try {
              SourceTree res=(SourceTree)sourceTreeClass.newInstance();
              sourceTreePool.put(id,res);
          } catch (InstantiationException e) {
              throw new RuntimeException("SourceTree.getFromPool "+e);
          } catch (IllegalAccessException e) {
              throw new RuntimeException("SourceTree.getFromPool "+e);
          }
      }
      // reset the tree
      SourceTree ret=(SourceTree)sourceTreePool.get(id);
      if(ret.getVisibleRowCount()!=8) {
          ret.setVisibleRowCount(8);
      }
      ret.setSelectedValue(null);
      ret.setEnabled(true);
      return ret;
  }


  public SourceTree(){
      this(DataSourcePool.global);
  }

  public SourceTree(DataSourcePool pool) {
      super();
      rootNode = new DefaultNode();
    treeModel = new DefaultTreeModel(rootNode);
    setModel(treeModel);
    // We don't want to see the root node, it is here to hold the other
    // interesting ones
    setRootVisible(false);
    setShowsRootHandles(true);

    this.pool = pool;
    pool.addListener(this);

    //filter
    filterPattern = new SourceFilterPattern();
   
    for (Iterator it = pool.dataSources().iterator(); it.hasNext(); ) {
      addSource((DataSource)it.next());
    }

    for (Iterator it = pool.dataSourceCollections().iterator(); it.hasNext(); ) {
      addCollection((DataSourceCollection)it.next());
    }
    treeModel.reload();

    setTransferHandler(new SourceTransferHandler());
    setDragEnabled(true);

    setCellRenderer(createRenderer());

    MouseListener ml = new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        JComponent c = (JComponent)e.getSource();
        if (c != SourceTree.this) return;
        TreePath path = getPathForLocation(e.getX(), e.getY());
        if ((e.getModifiers() & MouseEvent.BUTTON3_MASK) == MouseEvent.BUTTON3_MASK) {
          if (path!=null) setSelectionPath(path);
          boolean locked = false;
          if (getSelectionPath()!=null) {
            Object node = getSelectionPath().getLastPathComponent();
            if (node instanceof SourceNode) {
              if (((SourceNode)node).isLocked()) {
                locked = true;
              }
            }
          }
          if (!locked) doPopup(e.getX(), e.getY());
          return;
        }
      }

      public void mouseExited(MouseEvent e) {
        setCursor(Cursor.getDefaultCursor());
      }
    };
   
    addMouseListener(ml);

    MouseMotionListener mml = new MouseMotionAdapter() {
      public void mouseMoved(MouseEvent e) {
        JComponent c = (JComponent)e.getSource();
        if (c != SourceTree.this) return;
        TreePath path = getPathForLocation(e.getX(), e.getY());
        if (path!=null) {
          Object node = path.getLastPathComponent();
          if (node instanceof SourceNode) {
            if (((SourceNode)node).isLocked()) {
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
              return;
            }
          }
        }
        setCursor(Cursor.getDefaultCursor());
      }
    };
    addMouseMotionListener(mml);

    registerKeyboardAction(
      this,
      "d",
      KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0),
      WHEN_FOCUSED
    );
    registerKeyboardAction(
      this,
      "d",
      KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE,0),
      WHEN_FOCUSED
    );

  }

    /**
   * Select the given user object in the tree, if it exists. Default SourceTree implementation
   * only contains data source and collections, but any object is accepted (nothing will
   * happen if it is not found).
   */
  public void setSelectedValue(Object o) {
    if (o==null) {
      setSelectionPath(null);
      return;
    }
    for (Enumeration e = rootNode.depthFirstEnumeration(); e.hasMoreElements();) {
      Object elt = e.nextElement();
      if (!(elt instanceof DefaultMutableTreeNode)) continue;
      DefaultMutableTreeNode node = (DefaultMutableTreeNode)elt;
      Object u = node.getUserObject();
      if ((u!=null) && (u.equals(o))) {
        TreePath path = new TreePath(node.getPath());
        scrollPathToVisible(path);
        setSelectionPath(path);
        return;
      }
    }
  }

  /**
   * Select the given source or collection in the tree, if it exists, using its id.
   */
  public void setSelectedValueById(String id) {
    if (id==null) return;
    for (Enumeration e = rootNode.depthFirstEnumeration(); e.hasMoreElements();) {
      Object elt = e.nextElement();
      if (!(elt instanceof DefaultMutableTreeNode)) continue;
      DefaultMutableTreeNode node = (DefaultMutableTreeNode)elt;
      if (id.equals(DataInfo.getId(node.getUserObject()))) {
        TreePath path = new TreePath(node.getPath());
        scrollPathToVisible(path);
        setSelectionPath(path);
        return;
      }
    }
  }


  /**
   *  Runs through the tree to lock or unlock Nodes
   */
  protected void recursiveLock(DefaultMutableTreeNode n, Object o, boolean state) {
    if (n==null) return;
    if ((n.getUserObject()==o) && (n instanceof SourceNode)) {
      ((SourceNode)n).setLocked(state);
      return;
    }
    if (!n.getAllowsChildren()) return;
    Enumeration e = n.children();
    if (e==null) return;
    while (e.hasMoreElements())
      recursiveLock((DefaultMutableTreeNode)e.nextElement(), o, state);
  }

  /**
   *  Locks a Data Source or Data Source Collection
   *  The lock can be removed with the unlock function
   *  A locked Data Source or Collection cannot be used
   *  @param o The data source or data source collection to lock
   */
  public void lock(Object o) {
    recursiveLock(rootNode, o, true);
    repaint();
  }

  /**
   *  Unlocks a Data Source or Data Source Collection
   *  @param o The data source or data source collection to lock
   */
  public void unlock(Object o) {
    recursiveLock(rootNode, o, false);
    repaint();
  }

  /**
   *  Checks if a Data Source or Data Source Collection is locked
   *  @param o The data source or data source collection to look at
   */
  public boolean isLocked(Object o) {
    return recursiveIsLocked(rootNode, o);
  }


  /**
   *  Runs through the tree to check if a source or collection is lock or unlocked
   */
  protected boolean recursiveIsLocked(DefaultMutableTreeNode n, Object o) {
    if (n==null) return false;
    if ((n.getUserObject()==o) && (n instanceof SourceNode)) {
      return ((SourceNode)n).isLocked();
    }
    if (!n.getAllowsChildren()) return false;
    Enumeration e = n.children();
    if (e==null) return false;
    while (e.hasMoreElements())
      if (recursiveIsLocked((DefaultMutableTreeNode)e.nextElement(), o))
        return true;
    return false;
  }


  /** For subclasses to specialize. Does nothing by default. */
  protected void doPopup(int x, int y) {
  }


  /**
   * Iterates over the root node children and removes those with the
   * specified user object
   */
  protected void removeNodesWithUserObject(Object o) {
      // Reset filter
      setFilterValidity(false);

    // Don't remove the nodes while iterating, safer to do it after?
    // May be useless, a pity I'm too lazy to investigate...
    Vector nodes = new Vector();
    for (Enumeration e = rootNode.children(); e.hasMoreElements();) {
      DefaultMutableTreeNode child = (DefaultMutableTreeNode)e.nextElement();
      if (child.getUserObject()==o) nodes.add(child);
    }
    for (Iterator it = nodes.iterator(); it.hasNext();)
      rootNode.remove((MutableTreeNode)it.next());
   
   
    setFilterValidity(true);
  }

  protected void addSource(DataSource ds) {
    // Unlike rootNode.add, this handles tree events for tree listeners
     
      setFilterValidity(false);
     
    if(ds.isCompound()){
      treeModel.insertNodeInto(
          new CompoundDataSourceNode(ds, ""),
          rootNode,
          rootNode.getChildCount()
        );
     
    } else{
      treeModel.insertNodeInto(
          new DataSourceNode(ds, ""),
          rootNode,
          rootNode.getChildCount()
        );
    }
   
    setFilterValidity(true);
  }

  protected void addCollection(DataSourceCollection dsc) {
    // Unlike rootNode.add, this handles tree events for tree listeners

      setFilterValidity(false);
     
    if(dsc.isCompound()){
      treeModel.insertNodeInto(
          new CompoundCollectionNode(dsc, ""),
          rootNode,
          rootNode.getChildCount()
      );
    }
    else {
      treeModel.insertNodeInto(
          new CollectionNode(dsc, ""),
          rootNode,
          rootNode.getChildCount()
      );
    }
   
    setFilterValidity(true);
  }

  protected void changeSource(DataSource ds, DataSource old) {
    for (Enumeration e = rootNode.children(); e.hasMoreElements();) {
      DefaultMutableTreeNode child = (DefaultMutableTreeNode)e.nextElement();
      if (child.getUserObject()==old) ((DataSourceNode)child).changeSource(ds);
    }
  }

  protected void changeCollection(DataSourceCollection dsc, DataSourceCollection old) {
    for (Enumeration e = rootNode.children(); e.hasMoreElements();) {
      DefaultMutableTreeNode child = (DefaultMutableTreeNode)e.nextElement();
      if (child.getUserObject()==old) ((CollectionNode)child).changeCollection(dsc);
    }
  }

  /**
   * Return true if the selected values are child of the root node
   * @return  true if the selected values are child of the root node
   */
  protected boolean selectionIsRootChild(){
      boolean res = false;
      TreePath[] paths = getSelectionPaths();

      if (paths.length > 0){
          res = true;
          for(int i=0;i<paths.length && res; i++){
              TreeNode node = (TreeNode)paths[i].getLastPathComponent();
              res &=  rootNode.isNodeChild(node);
          }
      }
      return res;
  }
 
  public Object getSelectedSourceOrCollection() {
    if (getSelectionPath()==null) return null;
    Object node = getSelectionPath().getLastPathComponent();
    if (node==null) return null;
    if (node instanceof DataSourceNode) {
      return ((DataSourceNode)node).getUserObject();
    }
    if (node instanceof CollectionNode) {
      return ((CollectionNode)node).getUserObject();
    }
    return null;
  }

  // DataSourcePoolListener interface
  public void dataSourcePoolNotification(DataSourcePoolEvent e) {
    switch (e.action) {
      case DataSourcePoolEvent.ADD_SOURCE:
        addSource(e.source);
        break;
      case DataSourcePoolEvent.ADD_COLLECTION:
        addCollection(e.collection);
        break;
      case DataSourcePoolEvent.REMOVE_SOURCE:
        removeNodesWithUserObject(e.source);
        break;
      case DataSourcePoolEvent.REMOVE_COLLECTION:
        removeNodesWithUserObject(e.collection);
        break;
      case DataSourcePoolEvent.CHANGE_SOURCE:
        changeSource(e.source, e.oldSource);
        break;
      case DataSourcePoolEvent.CHANGE_COLLECTION:
        changeCollection(e.collection, e.oldCollection);
        break;
    }

    reload(true);
  }


  /**
   *
   * Re-assign tree nodes visibility regarding the current filter
     * and notify all tree listeners that the model has changed.
     *
   * @param reloadAllNodes - if true all tree node visibility are updated, otherwise update only
   * the visibility of visible nodes
   */
  public void reload(boolean reloadAllNodes) {
      // Keep selection
      TreePath sel = this.getSelectionPath();

      // Update all node visibility
      if (reloadAllNodes){
          setTreeNodeVisibility(rootNode, true);
      }
      updateTreeNodeVisibility(rootNode);
           
      // reload model
      treeModel.reload();

      // restore selection, if still present
      setSelectionPath(sel);
  }
 
 
  protected void setTreeNodeVisibility(DefaultNode node, boolean isVisible){
      node.setIsVisible(isVisible);
      Enumeration e = node.children();
      while (e.hasMoreElements()) {
          SourceNode childNode = (SourceNode) e.nextElement();
          setTreeNodeVisibility(childNode, isVisible);
     
  }
 
  protected boolean updateTreeNodeVisibility(DefaultNode node){
      boolean res = false;
     
      if (node.isVisible){   // if node not visible do not change its visibility
          res = filterPattern.acceptAll() || filterPattern.matches(node.getNodePath());
         
          Enumeration e = node.children();
          while (e.hasMoreElements()) {
              SourceNode childNode = (SourceNode) e.nextElement();
              res |= updateTreeNodeVisibility(childNode); // node is visible if at least one sub node is visible
         
       
          // Set node visibility
          node.setIsVisible(res);
      }
      return res;
  }

  public void removeAllTreeSelectionListeners(){
    TreeSelectionListener[] sl=getTreeSelectionListeners();
    if(sl!=null){
      for(int i=0;i<sl.length;i++){
        this.removeTreeSelectionListener(sl[i]);
      }
    }
  }

  // ActionListener interface
  public void actionPerformed(ActionEvent e){

      String cmd = e.getActionCommand();
      if (cmd.equals("d") && selectionIsRootChild()) {
          Object o = getSelectedSourceOrCollection();

          if (!(o==null || isLocked(o))){
              if (o instanceof DataSource) {
                  pool.removeDataSource((DataSource)o);

              } else if (o instanceof DataSourceCollection) {
                  pool.removeDataSourceCollection((DataSourceCollection)o);
              }
          }
      }  
  }

  /** For subclasses to specialize*/
  protected TreeCellRenderer createRenderer() {
    return new DefaultTreeCellRenderer();
  }


 
  protected class DefaultNode extends DefaultMutableTreeNode {
      /**
         * A string representation of node path (e.g "a.b.test")
         */
        String nodePath;
        protected boolean isVisible = true;
       
        public DefaultNode(){
            super();
            nodePath = "";
        }

        public DefaultNode(Object o, boolean allowsChildren, String parentNodePath) {
            super(o, allowsChildren);
            nodePath = parentNodePath + ( (!parentNodePath.equals("") && !getNodeId().equals("") )? "." : "" ) + getNodeId();
        }

        /**
         * Used to get the string representation of this node when filtering the tree
         * Sub classes can overload this method to specify  the node text value
         * @return
         */
        protected String getNodeId(){
            return toString();
        }

        /* (non-Javadoc)
         * @see javax.swing.tree.DefaultMutableTreeNode#getChildAt(int)
         */
        public TreeNode getChildAt(int index) throws ArrayIndexOutOfBoundsException{
            TreeNode res = null;

            if (children == null) {
                throw new ArrayIndexOutOfBoundsException("node has no children");
            }
            int realIndex = -1;
            int visibleIndex = -1;
            Enumeration e = children.elements();
            while (e.hasMoreElements() && (res == null)) {
                SourceNode node = (SourceNode) e.nextElement();
                if (node.isVisible() ) {
                    visibleIndex++;
                }
                realIndex++;
                if (visibleIndex == index) {
                    res =  (TreeNode) children.elementAt(realIndex);
                }
            } 
            if (res == null){
                throw new ArrayIndexOutOfBoundsException("index unmatched");
            }
            return res;
        }


        /**
         * Return whether or not the node shall be displayed in the source tree
         * @return
         */
        protected boolean isVisible(){
           return isVisible;
        }
       
        protected void setIsVisible(boolean isVisible){
            this.isVisible = isVisible;
        }
       
       
        /* (non-Javadoc)
         * @see javax.swing.tree.DefaultMutableTreeNode#getChildCount()
         */
        public int getChildCount(){
            int count = 0;
           
            if (children != null) {
                Enumeration e = children.elements();

                while (e.hasMoreElements()) {
                    SourceNode node = (SourceNode) e.nextElement();

                    if (node.isVisible() ) {
                        count++;
                    }
                }
            }
            return count;   
        }
       
       
        public String getNodePath(){
            return nodePath;
        }
  }
  /**
   * A SourceNode is a mutable node which can be hidden and locked
   * @author zxpletran007
   *
   */
  protected class SourceNode extends DefaultNode {

    /**
     * A node can be locked
     */
    boolean locked;


    /**
     * @param userObject an Object provided by the user that constitutes
     *        the node's data
     * @param allowsChildren if true, the node is allowed to have child
     *        nodes -- otherwise, it is always a leaf node
     * @param parentNodePath - A string representation of parent node path.
     */
    SourceNode(Object o, boolean allowsChildren, String parentNodePath) {
        super(o, allowsChildren, parentNodePath);
        setLocked(false);
    }

    public void setLocked(boolean b) {
      locked = b;
    }

    public boolean getLocked() {
      return locked;
    }
   
    /**
     * returns true if this node is locked, or one of its parents
     */
    public boolean isLocked() {
      if (locked) return true;
      TreeNode tn = getParent();
      if (tn==null) return false;
      if (tn instanceof SourceNode) return ((SourceNode)tn).isLocked();
      return false;
    }
  }
   
 
  protected class DataSourceNode extends SourceNode {
    DataSourceNode(DataSource source, String parentNodePath) {
      this(source, false, parentNodePath); // do not allow children
    }

    DataSourceNode(DataSource source, boolean allowsChildren, String parentNodePath) {
      super(source, allowsChildren, parentNodePath);
    }

    public String toString() {
      if (userObject==null) return "DataSource";
      String ret = DataInfo.toString((DataSource)userObject);

      if (ret!=null){
        if (((DataSource)userObject).isAuxiliary()){
          int dot = ret.lastIndexOf(".");
          if (dot!=-1)
            ret = ret.substring(dot+1);
        }
        return ret;
      }
      ret = userObject.getClass().getName();
      int dot = ret.lastIndexOf(".");
      if (dot!=-1) return ret.substring(dot+1);
      return ret;
    }

    public void changeSource(DataSource ds) {
      setUserObject(ds);
    }
  }
 
  protected class CompoundDataSourceNode extends DataSourceNode{

    CompoundDataSourceNode(DataSource source, String parentNodePath){
      super(source, true, parentNodePath); // allow children
      for(Iterator it=source.getAuxiliarySources().iterator();it.hasNext();)
        add(new DataSourceNode((DataSource)it.next(), nodePath));
    }

    public void changeSource(DataSource ds) {
      super.changeSource(ds);
      removeAllChildren();
      for(Iterator it=ds.getAuxiliarySources().iterator();it.hasNext();)
        add(new DataSourceNode((DataSource)it.next(), nodePath));
    }

    public boolean isLocked() {
      Enumeration e = children();
      if (e!=null) while (e.hasMoreElements()) {
        Object child = e.nextElement();
        if (child instanceof SourceNode)
          if (((SourceNode)child).getLocked()) return true;
      }
      return super.isLocked();
   
  }

  protected class CollectionNode extends SourceNode {

    CollectionNode(Object o, String parentNodePath) {
      super(o, true, parentNodePath); // allow children
    }

    CollectionNode(DataSourceCollection collection,  String parentNodePath) {
      this((Object)collection, parentNodePath);
      setSourceNodes(collection.iterator());
    }

    public String toString() {
      if (userObject==null) return "DataSourceCollection";
      String ret = DataInfo.getLabel((DataSourceCollection)userObject);
      if (ret!=null) return ret;
      ret = userObject.getClass().getName();
      int dot = ret.lastIndexOf(".");
      if (dot!=-1) return ret.substring(dot+1);
      return ret;
    }

    public void changeCollection(DataSourceCollection dsc) {
      removeAllChildren();
      setUserObject(dsc);
      setSourceNodes(dsc.iterator());
    }

    protected void setSourceNodes(Iterator it){
      while(it.hasNext()){
        addDataSource((DataSource)it.next());
      }
    }

    protected void addDataSource(DataSource ds){
        DataSourceNode dsn;
        if(ds.isCompound()){
            dsn = new CompoundDataSourceNode(ds, nodePath);
        }
        else{
            dsn = new DataSourceNode(ds, nodePath);
        }
        add(dsn);
    }

    /**
     * A collection node is locked if one of its source is locked
     */
    public boolean isLocked() {
      Enumeration e = children();
      if (e!=null) while (e.hasMoreElements()) {
        Object child = e.nextElement();
        if (child instanceof SourceNode)
          if (((SourceNode)child).getLocked()) return true;
      }
      return super.isLocked();
    }

  }

  protected class CompoundCollectionNode extends CollectionNode {

    CompoundCollectionNode(DataSourceCollection collection, String parentNodePath) {
      super((Object)collection, parentNodePath);
            nodePath = parentNodePath;  // we do not take in account a collection name in source filtering
      setChildNodes(collection.getCollectionContainers().iterator());
    }


    CompoundCollectionNode(DataSourceCollection.Container ct,  String parentNodePath) {
      super((Object)ct, parentNodePath);
     
      Collection c=ct.getChildren();
      if(c!=null)
        setChildNodes(c.iterator());
    }

    public String toString() {
      if(userObject instanceof DataSourceCollection.Container){
        return userObject.toString();
      }
      return super.toString();
    }
   
    /* (non-Javadoc)
     * @see simtools.ui.SourceTree.DefaultNode#getNodeText()
     */
    protected String getNodeId(){
        String res;
        if (( (userObject) instanceof DataSourceCollection.Container) && ((DataSourceCollection.Container)userObject).isVirtual()){
            res = "";
        } else {
            res = toString();
        }
        return res;
    }

    private void removeAllChildrenRecursively(){
      Enumeration e = children();
      if (e!=null) while (e.hasMoreElements()) {
        Object child = e.nextElement();
        if (child instanceof CompoundCollectionNode){
          ((CompoundCollectionNode)child).removeAllChildrenRecursively();
        }
      }
      removeAllChildren();
    }

    public void changeCollection(DataSourceCollection dsc) {
      removeAllChildrenRecursively();
      setUserObject(dsc);
      setChildNodes(dsc.getCollectionContainers().iterator());
    }

    protected void setChildNodes(Iterator it){
      while(it.hasNext()){
        Object o=it.next();

                if(o instanceof DataSourceCollection.Container){
          add(new CompoundCollectionNode((DataSourceCollection.Container)o, nodePath));
        }
        else{
          addDataSource((DataSource)o);
        }
      }
    }

    public boolean isLocked() {
      Enumeration e = children();
      if (e!=null) while (e.hasMoreElements()) {
        Object child = e.nextElement();
        if (child instanceof CompoundCollectionNode){
          if(((CompoundCollectionNode)child).isLocked()){
            return true;
          }
        }
        else if (child instanceof SourceNode)
          if (((SourceNode)child).getLocked()) return true;
      }
      return false;
    }
  }

  protected class SourceTransferHandler extends TransferHandler {

    protected Transferable createTransferable(JComponent c) {
      if (c!=SourceTree.this) return null;
      return new SourceTransferable();
    }

    public int getSourceActions(JComponent c){
      return COPY;
    }
  }

  protected class SourceTransferable implements Transferable {

    /* (non-Javadoc)
     * @see java.awt.datatransfer.Transferable#getTransferDataFlavors()
     */
    public DataFlavor[] getTransferDataFlavors() {
      Object node = getSelectionPath().getLastPathComponent();
      if (node==null) return new DataFlavor[0];
            //If there is a selected data, the available data flavors will be the data itself, and a string.
      DataFlavor[] ret = new DataFlavor[2];
      if (node instanceof DataSourceNode) ret[0] = new DataFlavor(DataSource.class, node.toString());
      else if (node instanceof CollectionNode) ret[0] = new DataFlavor(DataSourceCollection.class, node.toString());
      else ret[0] = DataFlavor.stringFlavor; // error, unknown object => as string
            //Add the String dataFlavor, to also export data path.
            ret[1] = DataFlavor.stringFlavor;
      return ret;
    }

    public boolean isDataFlavorSupported(DataFlavor flavor) {
      Object node = getSelectionPath().getLastPathComponent();
      if (node==null) return false;
      if (node instanceof DataSourceNode)
        return DataSource.class.equals(flavor.getRepresentationClass());
      if (node instanceof CollectionNode)
        return DataSourceCollection.class.equals(flavor.getRepresentationClass());
      return false;
    }

    /* (non-Javadoc)
     * @see java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer.DataFlavor)
     */
    public Object getTransferData(DataFlavor flavor) {
      //The result of the method
            Object result = null;
            //retrieve the selected data.
            Object selectedData = getSelectedSourceOrCollection();
            if(selectedData != null){
                //In case of a dataSource, and dataSource flavor, return the dataSource
                if ((selectedData instanceof DataSource) && DataSource.class.equals(flavor.getRepresentationClass())) {
            result = selectedData;
          }else if ((selectedData instanceof DataSourceCollection) && DataSourceCollection.class.equals(flavor.getRepresentationClass())) {
                    //Else for a dataSourceCollection, and if flavor is a collection, return collection.
            result = selectedData;
          }else if(flavor.equals(DataFlavor.stringFlavor)){
              //Else, if we need a String representation.
                    //return the label of the data.
                        result = DataInfo.getLabel(selectedData);
                }
            }
            //return the result
            return result;
    }
  }

    /**
     * Set filter value and reload the tree
     * @param filterValue
     */
    public void setFilterValue(String filterValue) {
       
        boolean reloadAll = !filterValue.startsWith(currentFilterValue);
        currentFilterValue = filterValue;
        filterPattern.setPattern(filterValue);
       
        reload(reloadAll);
    }
   
    /**
     * Set filter value and reload the tree
     * @param filterValue
     */
    public void setFilterValidity(boolean isValid) {
        filterPattern.setValidity(isValid);
        reload(true);
    }
   
   
    /**
     *  All nodes are expanded
     */
    public void expandAll(){
        expandAll(new TreePath(rootNode));
    }
   
    /**
     *  All nodes are collapsed
     */
    public void collapseAll(){
        int row = getRowCount() - 1;
        while (row >= 0) {
            collapseRow(row);
            row--;
        }
    }

    private void expandAll(TreePath parent) {
        TreeNode node = (TreeNode)parent.getLastPathComponent();
        boolean hasAuxiliaryDsNodes = node instanceof DataSourceNode && ((DataSource)((DataSourceNode) node).getUserObject()).isCompound();

        if ((node.getChildCount() >= 0) && !hasAuxiliaryDsNodes) {
            for (Enumeration e=node.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode)e.nextElement();
                TreePath path = parent.pathByAddingChild(n);
                expandAll(path);
            }
        }

        // Do not expand auxiliary sources
        if (!hasAuxiliaryDsNodes){
            expandPath(parent);
        }
    }
   
   
    public static interface FilterPattern{

        /**
         * @return true if the pattern does accept any value
         */
        public boolean acceptAll();


        /**
         * @param a given string value
         * @return true if the pattern does accept he given string
         */
        public boolean matches(String value);

        /**
         * Set the pattern value
         * @param pattern
         */
        public void setPattern(String pattern);
       
        public void setValidity(boolean isValid);
       
       
    }
   
   
    /**
     * This filter accepts any kind of string value.
     * Following 2 characters have a special signification:
     * <ul>
     <li> The wild card (*): equivalent to any sequence of character (zero to several characters)
     *  <li> The question mark card (?) : equivalent to any single character (one and only one character))
     * </ul>
     * @author zxpletran007
     *
     */
    public static class SourceFilterPattern implements FilterPattern{

        protected Pattern pattern;
        protected boolean isValid;
       
        public SourceFilterPattern(){
            this("");
        }
       
        public SourceFilterPattern(String pattern){
            setPattern(pattern);
            isValid = true;
        }

        public boolean matches(String value) {
            if (!isValid){
                return true;
            } else {
                return pattern.matcher(value.toUpperCase()).matches();
            }
        }

        public void setPattern(String pattern) {
            if (pattern == null){
                pattern = "";
            }

            // Convert the given pattern into a regular Java expression
            pattern = pattern.replaceAll("\\.", "\\\\.");
            pattern = pattern.replaceAll("\\?", ".");
            pattern = pattern.replaceAll("\\*", ".*");

            pattern = pattern.replaceAll("\\^", "\\\\^");
            pattern = pattern.replaceAll("\\+", "\\\\+");

            pattern = pattern.replaceAll("\\(", "\\\\(");
            pattern = pattern.replaceAll("\\)", "\\\\)");

            pattern = pattern.replaceAll("\\[", "\\\\[");
            pattern = pattern.replaceAll("\\]", "\\\\]");

            pattern = pattern.replaceAll("\\{", "\\\\{");
            pattern = pattern.replaceAll("\\}", "\\\\}");


            // Add an additional wild card at the end of the given pattern
            pattern = pattern.concat(".*");

            // pattern is not case sensitive
            pattern = pattern.toUpperCase();

            this.pattern =  Pattern.compile(pattern);
        }

        public boolean acceptAll(){
            return !isValid || pattern.pattern().equals(".*");
        }    

        public void setValidity(boolean isValid){
            this.isValid = isValid;
        }
       
    }
  
    public static void main(String args[]){

        System.out.println(new SourceFilterPattern("ee.rr(*").matches("ee.rr(0") );

        /*
        System.out.println( "efcgabbc matches with *abbc = " + new SourceFilterPattern("*abbc").matches("efcgabbc") );
        System.out.println( "efcgabbc matches with *abbc* = " + new SourceFilterPattern("*abbc*").matches("efcgabbc") );
        System.out.println( "efcgabbcdf matches with *abbc* = " + new SourceFilterPattern("*abbc*").matches("efcgabbcdf") );
        System.out.println( "efcgabbc matches with *abbc? = " + new SourceFilterPattern("*abbc?").matches("efcgabbc") );//false
        System.out.println( "efcgabbcm matches with *abbc? = " + new SourceFilterPattern("*abbc?").matches("efcgabbcm") );

        System.out.println( "a.bb.cc matches with *bb* = " + new SourceFilterPattern("*bb*").matches("a.bb.cc") );*/
    }
}

TOP

Related Classes of simtools.ui.SourceTree

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.